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
<h2>John Pepper</h2>
<p>Makes amazing <a href="http://www.boloco.com">burritos.</a></p>
<p>Is in touch with the blogosphere.</p>
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 <a> 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
<h2>John Pepper</h2> <p>Makes amazing <%= link_to 'burritos', 'http://www.boloco.com' %>.</p> <p>Is in touch with the blogosphere.</p>
That’s better. I got the HTML out of the controller and I can use #link_to instead of an <a> 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#render_to_string. 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.
class UsersController < ApplicationController
def create
@user = User.new params[:user]
if @user.save
RemoteApi.update_profile
:markup => render_to_string(:partial => 'user')
redirect_to user_path(@user)
else
render :action => :new
end
end
_user.rhtml
<h2>John Pepper</h2> <p>Makes amazing <%= link_to 'burritos', 'http://www.boloco.com' %>.</p> <p>Is in touch with the blogosphere.</p>
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, #render_to_string would allow you to do that.