I discovered recently that Ruby on Rails 3’s action views really don’t like it when you try to render them outside a controller. This was a problem, as I wanted to render a view in a Resque background task for caching.
You have to jump through a few hoops to make it work. The trick is to create a
subclass of ActionView::Base
and mix in a few things it’s missing:
module Renderer
# Renders a view.
def self.render options = {}
# Pass a hash of local variables as :assigns.
assigns = options.delete(:assigns) || {}
# Create a view.
view = view_class.new(
ActionController::Base.view_paths, assigns
)
# Mix in other helpers you need.
view.extend ApplicationHelper
view.extend CustomHelper
# Render.
view.render options
end
# Creates a subclass of ActionView::Base with route
# helpers mixed in.
def self.view_class
@view_class ||= Class.new ActionView::Base do
include Rails.application.routes.url_helpers
end
end
end
You can then use it from wherever:
Renderer.render(
template: 'users/show',
assigns: { user: @logged_user }
)
That’s it. Not quite clean but at least it’s short.