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

create.rjs

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

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.

Jared Carroll

Pair with one of our expert developers to level up your skills with Coaching by thoughtbot. Save time learning best practices and techniques for reducing technical debt in Ember, Ruby, Haskell, and Go in 1-on-1 sessions tailored to your goals.