GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS

Written by thoughtbot

she's a beauty

Recently I was writing an action in one of my controllers that needed to do a POST to a remote API.

One of the parameters in that POST was a block of HTML.

The first pass was similar to this (ignoring execption handling for the remote call for now):


class UsersController < ApplicationController

  def create
    @user = User.new params[:user]
    if @user.save
      markup =<<-EOS
        

John Pepper

Makes amazing burritos.

Is in touch with the blogosphere.

EOS RemoteApi.update_profile :markup => markup redirect_to user_path(@user) else render :action => :new end end end

I don’t like that HTML in my controller. Plus that tag is terrible, I want to use #link_to but that’s not available in controllers (and it shouldnt' be).

Second pass:


class UsersController < ApplicationController

  def create
    @user = User.new params[:user]
    if @user.save
      RemoteApi.update_profile
        :markup => render(:partial => 'user')
      redirect_to user_path(@user)
    else
      render :action => :new
    end
  end

end

_user.rhtml

 

John Pepper

Makes amazing <%= link_to 'burritos', 'http://www.boloco.com' %>.

Is in touch with the blogosphere.

That’s better. I got the HTML out of the controller and I can use #link_to instead of an tag.

But wait: ActionController::DoubleRenderError. You can’t call render and/or redirect multiple times in an action (as a side, whoever wrote ActionController::DoubleRenderError is awesome - that is the best error message of any Rails exception).

After looking through the docs i found ActionController::Base#rendertostring. This beauty is the same as #render but does not actually send the result as the response body i.e. it doesn’t count as a #render call in an action, allowing you to avoid the ActionController::DoubleRenderError.

Third pass:


class UsersController < ApplicationController

def create @user = User.new params[:user] if @user.save RemoteApi.updateprofile :markup => rendertostring(:partial => 'user') redirectto user_path(@user) else render :action => :new end end

_user.rhtml

 

John Pepper

Makes amazing <%= link_to 'burritos', 'http://www.boloco.com' %>.

Is in touch with the blogosphere.

Sweet. Exactly what I wanted.

Someone else here at t-bot recommended using this strategy for flash messages. Since flash messages are just text, whenever they get more complicated than 1 sentence it might be good to put them in a partial to keep all that view code out of your controller, #rendertostring would allow you to do that.