Auto_complete through User.name

I’m attempting an auto_complete by user.name, but it’s not as simple as
it sounds. I’ve followed the great Railscast on the topic, and I do have
the ajaxiness working just fine when I search by ID (I was doing this
for testing purposes - I don’t want users using IDs to find each other,
luckily). My auto_complete field needs to work the same as the GitHub
‘Collaborator’ addition form (or the Facebook search), whereby we find
the user by user.name. My problem is that the user.name attribute is
only a method in my user.rb, it is not a unique attribute, nor does it
exist in the users table. So, we can’t identify a user through it, we
need the ID.

Further to this, the app has a Profile model for storing additional user
info (I’m beginning to hate this design - is it really necessary? I’m
only doing it because I was scared in to it from a security standpoint).
The Profile model has first_name and last_name. The User model only has
the :name attribute through the Profile model;

user.rb

def name
“#{profile.first_name} #{profile.last_name}”
end

So, on the front-end, my auto_complete form needs to find the users by
the user.name attribute, but when we select a user from the
auto_completed results, we also need to have the user.id hidden away
somewhere (a hidden field, perhaps?) whilst the user.name is displayed
in the auto_completed_text_field as visual feedback for the end user.

Any ideas on how I achieve this?

On Sat, Aug 23, 2008 at 5:16 PM, Neil C.
[email protected] wrote:

I’m attempting an auto_complete by user.name, but it’s not as simple as
it sounds. I’ve followed the great Railscast on the topic, and I do have
the ajaxiness working just fine when I search by ID (I was doing this
for testing purposes - I don’t want users using IDs to find each other,
luckily). My auto_complete field needs to work the same as the GitHub
‘Collaborator’ addition form (or the Facebook search), whereby we find
the user by user.name. My problem is that the user.name attribute is
only a method in my user.rb, it is not a unique attribute, nor does it
exist in the users table. So, we can’t identify a user through it, we
need the ID.

model_auto_completer addresses this:

http://agilewebdevelopment.com/plugins/model_auto_completer

I happen to be the author but I’d recommend it if I wasn’t anyway.

Xavier N. wrote:

On Sat, Aug 23, 2008 at 5:16 PM, Neil C.
[email protected] wrote:

I’m attempting an auto_complete by user.name, but it’s not as simple as
it sounds. I’ve followed the great Railscast on the topic, and I do have
the ajaxiness working just fine when I search by ID (I was doing this
for testing purposes - I don’t want users using IDs to find each other,
luckily). My auto_complete field needs to work the same as the GitHub
‘Collaborator’ addition form (or the Facebook search), whereby we find
the user by user.name. My problem is that the user.name attribute is
only a method in my user.rb, it is not a unique attribute, nor does it
exist in the users table. So, we can’t identify a user through it, we
need the ID.

model_auto_completer addresses this:

http://agilewebdevelopment.com/plugins/model_auto_completer

I happen to be the author but I’d recommend it if I wasn’t anyway.

Thanks, Xavier. The description of the plugin states it would do the
trick. I did come across model_auto_completer in my reading-rounding
prior to installing auto_complete, but I couldn’t find much in the way
of example use cases. Are there any blog posts on it? I’ve tried
Googling but I couldn’t find anything that I (as a newbie) could follow
along (I’m struggling to follow the docs on Rubyforge).

On Mon, Aug 25, 2008 at 7:37 AM, Neil C.
[email protected] wrote:

Thanks, Xavier. The description of the plugin states it would do the
trick. I did come across model_auto_completer in my reading-rounding
prior to installing auto_complete, but I couldn’t find much in the way
of example use cases. Are there any blog posts on it? I’ve tried
Googling but I couldn’t find anything that I (as a newbie) could follow
along (I’m struggling to follow the docs on Rubyforge).

I can help. Can you describe the User model and the form you want to
autocomplete users in?

Xavier N. wrote:

On Mon, Aug 25, 2008 at 7:37 AM, Neil C.
[email protected] wrote:

Thanks, Xavier. The description of the plugin states it would do the
trick. I did come across model_auto_completer in my reading-rounding
prior to installing auto_complete, but I couldn’t find much in the way
of example use cases. Are there any blog posts on it? I’ve tried
Googling but I couldn’t find anything that I (as a newbie) could follow
along (I’m struggling to follow the docs on Rubyforge).

I can help. Can you describe the User model and the form you want to
autocomplete users in?

Hi Xavier,

Sorry it’s taken so long to get back to your kind offer! This feature
was put at the back of the queue after I hit the problems outlined
above.

The auto_complete is being used in combination with an Invitation model.
Users invite each other to a Group and, right now, they select the
recipients (the ones they have permission to send invitations to) using
a select.

I was using the Railscast technique, the one without the controller
before_filter. There was an auto_complete on the field in the view, the
response was directed towards a ‘recipients’ action in the Invitation
controller, this collected users by ID (seeing as I can’t use user.name,
yet) and had a js formatted response & template which rendered a mini
user partial for each user, in @recipients, collected by the find.

I may be removing my Profile model altogether as, despite people saying
how it can be cleaner and more secure, just makes the code more complex
and introduces more finds for me (and makes accessing highly using User
info, like we’re doing here, potentially tricky). So I may have the
user.name as a column in the Users table soon - but I still won’t be
able to use the name attribute as something that could set the
‘recipient’ of an invitation.

Do you have a blog post on how to do this? I struggled with the
instructions because they didn’t seem to tell me what I needed to do.
e.g. I’m told to ‘assume’ the
auto_complete_belongs_to_for_book_author_name, but is that something I
need to install? This is something tons of people would want to use
(there has to be quite a few apps out there that don’t adhere to unique
a ‘login’ or ‘username’ per user), so I’m sure that getting (gitting) it
on GitHub, and doing a blog post on the ‘finding by user.name and
identifying by ID’ scenario, would prove pretty popular.

On Wed, Aug 27, 2008 at 9:02 AM, Neil C.
[email protected] wrote:

The auto_complete is being used in combination with an Invitation model.
Users invite each other to a Group and, right now, they select the
recipients (the ones they have permission to send invitations to) using
a select.

So that’s the form of the invitation with possibly more fields such as
the group ID and a message body? If yes, single or multiple
recipients?

Can you send the relationships between the involved models User,
Invitation, Group, More? I mean the relevant models and their related
has_many/belongs_to.

e.g. I’m told to ‘assume’ the
auto_complete_belongs_to_for_book_author_name, but is that something I
need to install?

You need to install the plugin and, eventually, dependencies. That’s
explained in its documentation:

http://model-ac.rubyforge.org/

Xavier N. wrote:

On Wed, Aug 27, 2008 at 9:02 AM, Neil C.
[email protected] wrote:

The auto_complete is being used in combination with an Invitation model.
Users invite each other to a Group and, right now, they select the
recipients (the ones they have permission to send invitations to) using
a select.

So that’s the form of the invitation with possibly more fields such as
the group ID and a message body? If yes, single or multiple
recipients?

Can you send the relationships between the involved models User,
Invitation, Group, More? I mean the relevant models and their related
has_many/belongs_to.

e.g. I’m told to ‘assume’ the
auto_complete_belongs_to_for_book_author_name, but is that something I
need to install?

You need to install the plugin and, eventually, dependencies. That’s
explained in its documentation:

http://model-ac.rubyforge.org/

Invitations only go to one recipient at a time.

Yes, everything else about the app works - it really is just this
problem of a fetching users by @user.name. I’m literally just about to
remove the Profile model that is associated with the User - e.g.
@user.profile.first_name, @user.profile.last_name - so I’ll soon have a
user.name in the database soon). Right now, however, the User.rb
contains a ‘name’ method which joins the profile.first_name and
profile.last_name together to create @user.name (it doesn’t work for me

  • hence why I’m going to remove it).

I was struggling with the instructions because the English was difficult
for me to follow. From the plugin description, it sounds like this
plugin was built for what I want, I just don’t understand the docs. I
appreciate it explains the methods but, unless I’m being stupid again,
it doesn’t seem to have a clear step by step installation, e.g. can I
change how the model_auto_completer_result interprets my records in the
view?

On Wed, Aug 27, 2008 at 6:49 PM, Neil C.
[email protected] wrote:

Invitations only go to one recipient at a time.

OK. I am going to assume there’s an Invitation model that has a user
ID in a field modelled as

class Invitation
belongs_to :recipient, …
end

Once the plugin(s) are installed and the application rebooted insert
this into the invitation form:

<%= belongs_to_auto_completer :invitation, :recipient, :name %>

In the current controller implement an action

def auto_complete_belongs_to_for_invitation_recipient_name
@recipients = @current_user.friends.all(…) # whatever
render :inline => ‘<%= model_auto_completer_result(@recipients,
:name) %>’
end

It doesn’t matter whether users have a “name” attribute, it is enough
they respond to :name for the inline template to work. Say

class User
def name
[last_name, first_name].compact.join(", ")
end
end

I’ve written all of this off the top of my head, there may be some
errors, you need to change the association name if needed, you may
need to configure a route if the controller is restful… but you see
the idea.

Xavier N. wrote:

On Wed, Aug 27, 2008 at 6:49 PM, Neil C.
[email protected] wrote:

Invitations only go to one recipient at a time.

OK. I am going to assume there’s an Invitation model that has a user
ID in a field modelled as

class Invitation
belongs_to :recipient, …
end

Once the plugin(s) are installed and the application rebooted insert
this into the invitation form:

<%= belongs_to_auto_completer :invitation, :recipient, :name %>

In the current controller implement an action

def auto_complete_belongs_to_for_invitation_recipient_name
@recipients = @current_user.friends.all(…) # whatever
render :inline => ‘<%= model_auto_completer_result(@recipients,
:name) %>’
end

It doesn’t matter whether users have a “name” attribute, it is enough
they respond to :name for the inline template to work. Say

class User
def name
[last_name, first_name].compact.join(", ")
end
end

I’ve written all of this off the top of my head, there may be some
errors, you need to change the association name if needed, you may
need to configure a route if the controller is restful… but you see
the idea.

Thanks. I got round to removing the Profile model altogether and my
@user.name attribute is created using a before_create and before_update
that combines the @user.first_name & @user.last_name in the User.rb. So
I have ‘proper’ :name column, now.

However, I’ve followed your instructions, and I’m seeing this;

‘undefined method `reflect_on_association’ for NilClass:Class’

And it’s cited here:
<%= belongs_to_auto_completer :invitation, :recipient, :name %>
in my /invitations/_form.html.erb

I have this in the application.rb (this was just for testing purposes -
I’ll put it in the correct controllers later - there’s a couple);

def auto_complete_belongs_to_for_invitation_recipient_name
@recipients = current_user.subscribers
render :inline => ‘<%= model_auto_completer_result(@recipients,
:name) %>’
end

Any ideas?

On Wed, Aug 27, 2008 at 11:37 PM, Neil C.
[email protected] wrote:

Thanks. I got round to removing the Profile model altogether and my
@user.name attribute is created using a before_create and before_update
that combines the @user.first_name & @user.last_name in the User.rb.

Do you know there’s before_save?

However, I’ve followed your instructions, and I’m seeing this;

‘undefined method `reflect_on_association’ for NilClass:Class’

And it’s cited here:
<%= belongs_to_auto_completer :invitation, :recipient, :name %>
in my /invitations/_form.html.erb

I guess @invitation is nil. The helper expects an actual Invitation
instance to figure stuff about the association. @invitation =
Invitation.new is enough.

I have this in the application.rb (this was just for testing purposes -
I’ll put it in the correct controllers later - there’s a couple);

def auto_complete_belongs_to_for_invitation_recipient_name
@recipients = current_user.subscribers
render :inline => ‘<%= model_auto_completer_result(@recipients,
:name) %>’
end

Don’t put it there, because methods inherited from
ApplicationController are not actions by definition. By the same price
put the method in InvitationsController.

Thanks a lot for this one. You just saved me a lot of time.

Mark

Xavier N. wrote:

On Wed, Aug 27, 2008 at 11:37 PM, Neil C.
[email protected] wrote:

Thanks. I got round to removing the Profile model altogether and my
@user.name attribute is created using a before_create and before_update
that combines the @user.first_name & @user.last_name in the User.rb.

Do you know there’s before_save?

However, I’ve followed your instructions, and I’m seeing this;

‘undefined method `reflect_on_association’ for NilClass:Class’

And it’s cited here:
<%= belongs_to_auto_completer :invitation, :recipient, :name %>
in my /invitations/_form.html.erb

I guess @invitation is nil. The helper expects an actual Invitation
instance to figure stuff about the association. @invitation =
Invitation.new is enough.

I have this in the application.rb (this was just for testing purposes -
I’ll put it in the correct controllers later - there’s a couple);

def auto_complete_belongs_to_for_invitation_recipient_name
@recipients = current_user.subscribers
render :inline => ‘<%= model_auto_completer_result(@recipients,
:name) %>’
end

Don’t put it there, because methods inherited from
ApplicationController are not actions by definition. By the same price
put the method in InvitationsController.

Hi Xavier, sorry it’s taken me so long to get back to this one. I’m now
seeing this;

undefined method `model_auto_completer_result’ for
#ActionView::Base:0x3d79058

This is my controller (before_filter)

def auto_complete_belongs_to_for_invitation_recipient_name
@invitation = Invitation.new
@recipients = current_user.friends
render :inline => ‘<%= model_auto_completer_result(@recipients,
:name) %>’
end

This is my form;

<%= belongs_to_auto_completer :invitation, :recipient, :name %>

Any more ideas?

On Sun, Aug 31, 2008 at 11:04 PM, Neil C.
[email protected] wrote:

Hi Xavier, sorry it’s taken me so long to get back to this one. I’m now
seeing this;

undefined method `model_auto_completer_result’ for
#ActionView::Base:0x3d79058

That was added in the last release (April 3).

Xavier N. wrote:

On Sun, Aug 31, 2008 at 11:04 PM, Neil C.
[email protected] wrote:

Hi Xavier, sorry it’s taken me so long to get back to this one. I’m now
seeing this;

undefined method `model_auto_completer_result’ for
#ActionView::Base:0x3d79058

That was added in the last release (April 3).

Xavier, do you mean I should check my plugin version is up to date? I
downloaded it less than a week ago.

On Mon, Sep 1, 2008 at 7:33 PM, Neil C.
[email protected] wrote:

Xavier, do you mean I should check my plugin version is up to date? I
downloaded it less than a week ago.

Hi Neil, nope the current release is from April 3, you have the last
release.

I wondered whether you were editing the text field and with the cursor
still there (so the field does not loose focus) you inmediately hit
the submit button.

– fxn (from Berlin)

Xavier N. wrote:

On Mon, Sep 1, 2008 at 7:33 PM, Neil C.
[email protected] wrote:

Xavier, do you mean I should check my plugin version is up to date? I
downloaded it less than a week ago.

Hi Neil, nope the current release is from April 3, you have the last
release.

I wondered whether you were editing the text field and with the cursor
still there (so the field does not loose focus) you inmediately hit
the submit button.

– fxn (from Berlin)

Cool, that’s one option down. I’ll check my implementation again, but,
the app was breaking before I got to the view - so I didn’t see or click
on the auto complete field. Obviously other people here have this
working (is it 2.1 compatible?) so I’ll give it another go later.

When I tried this (instead of using the model_auto_complete);

render :inline => ‘hello world’

I got the ‘hello world’ in the view (so no more error messages) but it
was the only thing in the view.

Xavier N. wrote:

On Tue, Sep 2, 2008 at 8:06 AM, Neil C.
[email protected] wrote:

Obviously other people here have this
working (is it 2.1 compatible?) so I’ll give it another go later.

Yeah, it works with 2.1 for sure.

Thanks - the plugin is up to date, I know it works on my version of
Rails, so I’ll let you know how I get on.

On Tue, Sep 2, 2008 at 8:06 AM, Neil C.
[email protected] wrote:

Obviously other people here have this
working (is it 2.1 compatible?) so I’ll give it another go later.

Yeah, it works with 2.1 for sure.

On Tue, Sep 2, 2008 at 11:30 PM, Neil C.
[email protected] wrote:

If I comment out the render :inline => ‘<%=
model_auto_completer_result(@recipients, :name) %>’ I get the normal
layout back. Is it a problem with loading the
auto_complete_belongs_to_for as a before_filter?

Just remove the before_filter macro call, and make
auto_complete_belongs_to_for_invitation_recipient_name public.

That method is called automatically by the helper through Ajax when
the user enters something into the field. You typically won’t call it
explicitly.

Neil C. wrote:

Xavier N. wrote:

On Tue, Sep 2, 2008 at 8:06 AM, Neil C.
[email protected] wrote:

Obviously other people here have this
working (is it 2.1 compatible?) so I’ll give it another go later.

Yeah, it works with 2.1 for sure.

Thanks - the plugin is up to date, I know it works on my version of
Rails, so I’ll let you know how I get on.

Xavier, I’m almost there now, except that the render :inline => ‘<%=
model_auto_completer_result(@recipients, :name) %>’ is taking over all
the view, rather than just rendering within the text field - so I’m only
seeing the names of the potential recipients of the Invitation in the
view, and nothing else (‘hello world’ style). This is how it is set up
at the moment;

/invitations/_form.html.erb

<% form_for :invitation, :url => group_invitations_path(@group) do |f|
%>
<%= belongs_to_auto_completer :invitation, :recipient, :name %>
<%= f.submit ‘Send Invitation’ %>
<% end %>

groups controller

before_filter :auto_complete_belongs_to_for_invitation_recipient_name

private

def auto_complete_belongs_to_for_invitation_recipient_name
@invitation = Invitation.new
@recipients = @current_user.friends
render :inline => ‘<%= model_auto_completer_result(@recipients,
:name) %>’
end

If I comment out the render :inline => ‘<%=
model_auto_completer_result(@recipients, :name) %>’ I get the normal
layout back. Is it a problem with loading the
auto_complete_belongs_to_for as a before_filter?