This is a nice little trick for simplifying your controllers. You’re not going to get new functionality, but it might make your code read a little easier.
Let’s assume we have a list action which lists blog entries. We just met this hilarious VC at Stirr and want him to be a blogger with us. It sure would be nice to be able to list posts by author, now that we’ve more than one.
An obvious solution is to start building case statements in our list action to add parameters to our Post#find call. Something like /posts/list?author=2? Here’s another option:
class PostsController < ApplicationController def list_by_author list :conditions => ['author_id = ?', params[:id]] end def list(find_options = {}) @posts = Post.find(:all, { :order => 'created_on desc' }.merge(find_options)) render :action => :list end end
As you can see, I’ve changed list to accept an optional hash parameter (find_options) and created a list_by_author method which simply calls list, passing it a hash. The passed hash will be merged with list’s other options unobtrusively.
This gives us /posts/list and /posts/list_by_author/2. From here on out, it’ll be dirt cheap to add new list types like list_by_month, list_by_year, or list_by_tag.
This trick is especially useful if your list action has additional logic, like sorting. The same logic and parameters will work with your new list_by actions just fine.
A nice side effect, thanks to Ruby, is that Hash#merge replaces any parameters in the receiver with those in the passed hash. This means, in the above example, we can replace the :order parameter with anything we want in a list_by action and still have everything work beautifully.
Have you looked into “with_scope” ? This is another way to organize, correct ?
Correct.
Chime in.