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"?
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.