Tuesday, July 01, 2008

will_paginate and searches through multiple models.

As Ryan Bates of railscast.com shows, using the will_paginate plugin with a simple search form is extremely easy, but what if you want to search for currencies through different linked models? for example, suppose we have two models, Topic and Post, a topic has_many post, and a post belongs_to a topic, we want to paginate topics using a form that will search in both model's content, not just the topic's one.

I will describe the method I used, off course there are more options outside, like using the acts_as_ferret plugin integrated with will_paginate, and also you can embeb ruby code with long SQL sentences. (even when the SQL method is faster, I enjoy using ruby code)

ok, let's do this really fast, you will need to put this file in your /lib directory and name it search.rb, it's the TextSearch's search library's code, now we can write in our topic's model file, something like:

require_dependency "search"

class Topic < ActiveRecord::Base
has_many :posts

validates_presence_of :title, :description
validates_uniqueness_of :title

searches_on :all
#searches_on :title
#searches_on :description

#the search method is defined by the /lib/search.rb file.
#the s_search parameter is the text to be matched.
#the method returns a collection of topics.
def self.search_and_paginate(s_search, page)
search(s_search, :include => [:posts]).paginate(:order => "created_at DESC",
:page => page, :per_page => 10)
end

end

(There are many ways using the search library, more examples are listed here.)

note you can miss the :include symbol, in that case you shouldn't use this method, just follow the railscast way.

Ok, we are passing the returned search's collection to the will_paginate's paginate method, then you should have in your controller something like:


def index
...
@topics = Topic.search_and_paginate(params[:search], params[:page])
...
end



Finally in your view,


<%= will_paginate @topics %>


And that's it!!