ActionController::MimeResponds is brilliant

Was a little bit blown away yesterday, by how smart the ActionController::MimeResponds module in Rails ActionPack really is. For the longest time when using respond_with (the younger sibling of respond_to,) I’ve been doing it wrong.

I’ve written code similar to this whenever I’ve needed to override the default behavior:

respond_to :html, :json

# .. other actions omitted for brevity

def create
  @discussion = Discussion.find(params[:discussion_id])
  @entry = @discussion.entries.create(params[:entry])

  respond_with @entry do |format|
    format.html do
      if @entry.new_record?
        render 'discussions/show'
      else
        redirect_to discussion_url(@discussion)
      end
    end
    format.json { render :json => @entry }
  end
end

My assumption was that if I needed to change the default behavior, I had to more or less mimic the behavior of respond_to (not to be confused with the respond_to as seen in the example above) which is to explicitly define behavior for each MIME type response. Well, it turns out that you only need to override that which deviates from the default behavior and the rest will still be handled as per the default. The respond_with block in the previous example can be simplified as follows:

respond_with @entry, :location => discussion_url(@discussion) do |format|
  if @entry.new_record?
    format.html { render 'discussions/show' }
  end
end

The only thing that deviates from the standard behavior, is the fact I want to render a template belonging to another controller and action (the one that initiated the HTTP POST) whenever the new entry wasn’t successfully created. The assumption being it most likely failed validation, and we need to present the validation errors to the user.

Why respond_with hasn’t been better documented in e.g. The Ruby on Rails Guides or in the API documentation is not known to me, but my best guess would be because this is a new feature in Rails 3, nobody has gotten around to it yet. I only found out about this behavior by looking at the source code, but for all I know this might be common knowledge and I’ve simply overlooked it somehow.