DRY Your Controllers

Tháng Hai 17, 2009

Source: http://errtheblog.com/posts/8-dry-your-controllers

I’ve been writing a lot of CRUDY tools lately. They all display a listing, allow you to delete an item, let you view an item, let you create an item, and let you edit an item. Standard Rails goodness. The thing is, all their ‘save’ methods are pretty different. Stuff needs to happen.

Creating a bunch of new.rhtml and edit.rhtml files wrapping a _form.rhtml partial got pretty old pretty fast. I decided I’d rather have new and edit wrap a save method and have a form.rhtml template which was capable of handling both actions.

First, the controller. This one’s for (you guessed) blog entries.

class EntriesController < ApplicationController
  def new; save end
  def edit; save end

  def save
    @entry = params[:id] ? Entry.find(params[:id]) : Entry.new

    if request.post?
      @entry.attributes = params[:post]

      return redirect_to :action => :list if @entry.save
    end

    render :action => :form
  end
end

Like I said, new and edit just wrap the save action. The save method figures out if it needs to instantiate a new entry or an existing entry based on the presence of params[:id]. If it’s a post request, it sets the attributes of the Entry object and then does some specific pre-save setup.

There are a few cool things about setting up your create / update actions this way. One is that on validation failure you’ll keep the url you want. For instance, if your create fails because a title is not present you will be shown your error messages while still on /entries/new (rather than something like /entries/create which can futz up a refresh).

Of course, we don’t get much benefit on the views side if we’re already wrapping a _form.rhtml partial. But it sure is nice to have a clean controller, even for simple things.