Render Rails Templates Anywhere (even in a model)

Monday, July 20th, 2009

I can only dream of actually having the time to properly update this blog, but for the moment I’m simply posting a snippet that has been very useful to me.

Even though I love Rails, I hate the way it locks you into only working within its paradigm, making it virtually impossible to break out of the MVC box even when it makes far more sense to do so. One particularly bothersome case is when you need (for whatever reason) to render an ActionView template outside of a controller.

For instance, in an application I’m working on I allow users to customize automatically sent emails. These emails are templated using a custom class that allows the user to insert predefined tags into the message that are automatically replaced with information such as the recipients name, address, etc. One such tag is replaced by a summary of all the users registration information, and this summary is simply an ActionView template. This leads to the sticky part. The template class is prepared by a class method of my model, which needs to provide a block to the template class capable of rendering this summary page.

Enter the render_anywhere method!

def render_anywhere(partial, assigns)
  view = ActionView::Base.new(Rails::Configuration.new.view_path, assigns)
  ActionView::Base.helper_modules.each { |helper| view.extend helper }
  view.extend ApplicationHelper
  view.render(:partial => partial)
end

Simply place this method in a file in your lib directory, or even in environment.rb, it really doesn’t matter. Then you can just call it (from literally anywhere) as shown below:

render_anywhere('/students/summary', { :student => student })

You can also add controller specific helpers if necessary, by simply adding more view.extend lines as above.

(thanks to Compulsivo for much of this code)

One Response

  1. david g - June 8th, 2010 at 9:30 pm

    I am trying to use this solution however it does not work in Rails 2.3.5 — The problem is Actionview::Base.helper_modules was deprecated awhile back. Any thoughts on how to make this work in Rails 2.3.5?

    Thanks