Search code examples
sqlruby-on-rails-3.1autocompletejquery-tokeninput

How do I write this query in Rails for auto-complete using JQuery Tokeninput?


I have a form with an "auto-complete" field that uses jQuery Tokeninput. The basic query, which just looks for Users whose name or username matches the typed text, is:

#users_controller.rb
def index
  @users = User.where("LOWER(name) like ? OR LOWER(username) like ?", "%#{params[:q].downcase}%", "%#{params[:q].downcase}%").order('name ASC').limit(10) if params[:q]

  respond_to do |format|
    format.html # index.html.erb
    format.json { render json: @users, :only => [:id, :name, :username] }

end

This works well.

My app also has a "follower model", and I want to limit which users show up in the autocomplete field so that only "reciprocal followers" are returned. A "reciprocal follower" is someone I follow who follows me back [(A follows B) AND (B follows A)].

I have a method in the User model that returns reciprocal followers for a user:

#user.rb
# Users relation to Relationships
has_many :relationships, :foreign_key => "follower_id", :dependent => :destroy
has_many :followed_users, :through => :relationships, :source => :followed
has_many :reverse_relationships, :foreign_key => "followed_id",
                                 :class_name  => "Relationship",
                                 :dependent => :destroy
has_many :followers, :through => :reverse_relationships, :source => :follower

def reciprocal_followers
  self.followers & self.followed_users
end

I can get reciprocal followers for the person typing the text:

@reciprocal_followers = current_user.reciprocal_followers

But how do I pare that list down according to what text has been typed? How do I integrate the existing autocomplete (@users = User.where...) query with @reciprocal_followers?

In English: "I want autocomplete to show a list of up to 10 reciprocal users whose name or username is like whatever the user has been typed in the autocomplete field".

How do I modify the query defining "@users" to limit according to "@reciprocal followers"?


Solution

  • Here's what I ended up working out:

    @users = current_user.reciprocal_followers.select {|u| u.name.downcase =~ /#{params[:q].downcase}/ || u.username.downcase =~ /#{params[:q].downcase}/}.sort_by { |u| [u.name, u.username] }.first(10) if params[:q]
    

    A friend also recommended I move this out of users_controller.rb and into relationships_controller.rb where I have "follow" and "unfollow" actions since I'm really looking for a list of relations that happen to be users (and not just looking to return users). If I leave it in users_controller.rb, I should probably move it out of the "index" action.