Keeping it RESTful
REST is now the standard way of doing things in Rails and I am a convert. I have always spent far too long worrying about the best way to write my applications, but now REST has come into my life and taken a whole universe of procrastination and indecision away from me.
So, these days when I see Rails code that is not RESTful, I look for ways to clean it up.
Take the following lines in a routes file:
map.connect '/posts/needs', :controller => 'posts', :action => 'needs' map.connect '/posts/offers', :controller => 'posts', :action => 'offers'
And the following methods in the posts
controller:
def needs @posts = Post.find(:all, :conditions => { :kind => "Need" } respond_to do <a href="format"> format.html { render :action => 'index'} end end def offers @posts = Post.find(:all, :conditions => { :kind => "Offer" } respond_to do </a>format<a href=" format.html { render :action => 'index'} end end
The only difference between these two methods is a difference in the “kind” of post. They can easily be refactored into a single index
method that handles both kinds of post:
def index @kind = params[:kind] @posts = Post.find(:all, :conditions => { :kind => "Offer" } respond_to do ">format</a> format.html end end
The “kind” is now identified from the :kind
paramater. This parameter can come from a query string, like this:
/posts?kind=Offer
But if you don’t want query strings in your URLs, then you can create new routes for each “kind”:
map.connect '/posts/offers', :controller => 'posts', :action => 'index', :kind => "Offer" map.connect '/posts/needs', :controller => 'posts', :action => 'index', :kind => "Need"
Or, if you prefer, you can define the routes in a single line:
map.connect '/posts/:kind', :controller => 'posts', :action => 'index', :kind => /Offer|Need/
Note the regular expression used to constrain what :kind the URL can contain and also note that the URLs required are now of the form ‘/posts/Offer’, rather than ‘/posts/offers’.
One final change is to give the route a name (in this case, “kinds”):
map.kinds '/posts/:kind', :controller => 'posts', :action => 'index', :kind => /Offer|Need/@
Allowing resources to be linked to like this:
<%= link_to "Offers", kinds_path('Offer') %>
As general rules of thumb, keep controllers and routes RESTful and use customized mappings sparingly (but that doesn’t mean don’t use them at all).