render right

Jared Carroll

One extension to Rails ActionController::Base#render method I don’t like is the new :update parameter. This is used to render inline RJS in an action like:

class CommentsController < ApplicationController

  def create
    @comment = Comment.new params[:comment]
    respond_to do |wants|
      if @comment.save
        wants.js do
          render :update do |page|
            page.insert_html :bottom, 'comments', render(:partial => 'comment',
                                                         :object => @comment)
            page[:errors].replace_html ''
            page[:comment_form].reset
          end
        end
      else
        wants.js do
          render :update do |page|
            page[:errors].replace_html @comment.errors.full_messages
          end
        end
      end
    end
  end

end

That’s a very simple AJAX comment submission. Instead of creating RJS templates in app/views/comments I just rendered the RJS inline in the action. I think this is bad because:

  1. look at how much longer the action is
  2. the nesting makes it a pain to read
  3. in this case the error display will be ugly because I can’t call view methods such as #error_messages_for in a controller so I’m forced to call ActiveRecord::Errors#full_messages.

I think it’s much better to use RJS views instead. Then the above action becomes:

class CommentsController < ApplicationController

  def create
    @comment = Comment.new params[:comment]
    respond_to do |wants|
      if @comment.save
        wants.js
      else
        wants.js { render :action => 'new.rjs' }
      end
    end
  end

end

In create.rjs:

page.insert_html :bottom, 'comments', render(:partial => 'comment',
                                             :object => @comment)
page[:errors].replace_html ''
page[:comment_form].reset

In new.rjs:

page[:errors].replace_html error_messages_for(:comment)

Then you say but it’s only a couple lines of RJS, why create 2 more files just for that?. My answer would be: do you ever write normal non-AJAX actions like this:

class PostsController < ApplicationController

  def show
    @post = Post.find params[:id]
    html =<<-EOS
      <h2>#{@post.title}</h2>

      #{@post.body}
    EOS
    render :text => html, :layout => 'application'
  end

end

Of course not.

In my opinion, the :text and :update parameter options in ActionController#Base should both be deprecated.