Let’s say I have a form where users can search for people whose name starts with a particular name string, for example, “Mi” would find “Mike” and “Miguel”. I would probably create a find statement like so:
find(:all, :conditions => ['name LIKE ?', "#{name}%"])
Let’s say the form also has two optional fields, hair_color and eye_color that can be used to further filter the results. Ignoring the name portion of the query, a find statement for people that can take in an arbitrary number of optional parameters might look like this:
find(:all, :conditions => { params[:person] })
Which for my two optional parameters would behave as the equivalent of this:
find(:all, :conditions => { :hair_color => hair_color, :eye_color => eye_color })
What I can’t figure out is how to merge these two kinds of queries where the required field, “name” is applied to the “like” condition above, and the optional hair_color and eye_color parameters (and perhaps others) can be added to further filter the results.
I certainly can build up a query string to do this, but I feel there must be a “rails way” that is more elegant. How can I merge mandatory bind parameters with optional parameters?
This is the perfect use of a named scope.
create a named scope in the model:
At this point you can call
And Rails will merge the queries for you.
Edit: Code for Waseem:
If the name is optional you could either omit the named scope from your method chain with an if condition:
Or you could redefine the named scope to do the same thing.
Update
Here is the Rails 3 version of the last code snippet: