Convention for RESTful search in Rails?
Sunday, July 22, 2007 at 7:12PM > There are unresolved decisions with respect to the restful controllers. In particular, what should the convention be for searching? A separate action? Or parameters passed to the index action?
I don't suppose a convention has been adopted for this yet? I'm just about to implement search in an application I'm working on and I'd rather go with the 2.0 convention now, rather than fight against it with my wrong decision later. :-)
**Update** Judging by the implementation of `ActiveResource#find` it's parameters passed to index, isn't it?
**Update 2** OK, so what's the elegant, reusable implementation for `FooController#index`, turning `params` into `find(:all, :conditions => ...)`?
**Update 3** I've started codifying what I'm doing into a plugin: [resource_search](http://svn.rubaidh.com/plugins/trunk/resource_search). It's still in its infancy.
Reader Comments (9)
Any thoughts about extending this to also search by foreign key objects? As a concrete example, I have a Business model that has a foreign key to an Address, and I want to be able to find all of a certain kind of business within 10 miles of me.
How would I specify that certain search parameters apply to the foreign key model?
Nice!
<
p>
I added this little helper to your form_helper.rb which (I hope) encapsulates the expected naming conventions for search field (and remembers their values)
<
p>
I'm having issues with
though - it's making a bit of a mess of the search parameters in the navigation links, losing rather than quoting the special characters. Is it something I'm doing wrong?
Oops, messed the formatting up a bit there. I think I'm encountering the same problem you referred to previously in
http://woss.name/2007/01/14/correct-route-generation-for-params-which-are-hashes/
Did you find a solution?
@Toby
I haven't tried this plugin yet, but if all the params are nested under the model name (model[x], model[y]), you can get at all of them by just doing:
find(:first, :conditions => params[:model])
Is that what you were talking about?
@Richie - The trouble I was having was that when using ActiveResource (i.e., the client API for REST web services) if I called:
Resource.find(:all, :params => {:key => :val})
it would generate a request to the application with the url:
GET http://server.com/resource?key=val
But resource_search would expect the parameter has to contain model[key] rather than just key.
I wanted to know a way of making this plugin work regardless of the format of the query string or the POST parameters.
I hope that makes more sense.
Toby
Hi Graeme. I was looking at this plugin today. Very nice. It is exactly the kind of thing I wanted to do on models in my application. In reading the comments and in using it I noted that you have to prefix the key/val with the model name. I have a little hack to let you do it this way or the ARes way that Toby mentions above.
Before I clean it up (it isn't much), are you still using/maintaining/accepting patches for this plugin?
Thanks for your hard work.
Don
Don: I am about to refactor the plugin with a number of improvements I've been needing for another project. Please do send your patch to me and I'll make sure it's incorporated. :-)
Neat plugin. For determining the model names from the controller, you might want to look at how the resource_controller plugin handles it. It opionally lets you specificy a different model from the one derived from the controller name, too.
For the SQL, you might want to look at the squirrel plugin just for fun. It's a neat plugin to Rubyize the conditions for AR#find. You can obtain just the SQL by using it with Model.find(:query) do foo == 'bar' end.conditions.to_sql
Thanks!
I know this plugin is more intended as a one-shot deal to allow for searching a model, but it might be nice to be able to override the SQL and produce a more crafted query per model. I added the followingly quickly:
My model (using squirrel plugin for SQL):
def self.search_scope_conditions(params={})
return nil if params.blank?
self.find(:query) do
last == params[:last]
end.conditions.to_sql
end
model.rb:
def with_search_terms(params)
conditions = search_scope_conditions(params)
with_scope :find => {:conditions => conditions} do
yield
end
end
Maybe I should make it accept a block or a symbol.
Just a thought.