1. Skip to navigation
  2. Skip to content

The ELC Community Blog

A knowledge exchange on Ruby on Rails and Agile Development


Rendering views without a web request in rails

by stevend on November 14, 2007

Why the heck do you want to do that?

Views are very well integrated into the rails framework, but they're only typically rendered when an http request comes in. ActionMailer is the main exception, but what if you want to render a view for use in another backend application? These days, document fragments are being used everywhere, and often times I'll need rendered HTML for a use other than just sending it back to the requesting user.

A solution: instantiate a controller and view

Controllers are just objects, and so are views. We can instantiate a controller, instantiate a view, then point the view to the controller and we're ready to go. The only think we're missing is the session and the request objects, but not every view needs those. I used this once for updating a facebook profile using a backgroundrb worker:

   1  class FakeView < ActionView::Base
   2    include SomeHelper
   3    include SomeOtherHelper
   4  end
   5  
   6  class FakeController < ActionController::Base
   7    def render_some_view
   8      action_view = FakeView.new(File.join(RAILS_ROOT, "app", "views"), {})
   9      action_view.instance_variable_set("@controller", self)
  10      markup = action_view.render(:partial => 'facebook/your_profile')    
  11    end
  12  end

By subclasses

   1  ActionView::Base
, you can mix helpers into the view class, making their methods available.

Another solution: use the test framework!

The rails TestProcess is the only place where views are rendered. If you really want to simulate a real experience when rendering a view, use the test process. First, you'll need an actual controller with an actual action you want to render in it, like this one:

   1  class FacebookController
   2    before_filter :login_required
   3    
   4    def your_profile    
   5    end
   6  end

Then, we create and instante a test as follows:

   1  class FacebookTest
   2    include ActionController::TestProcess
   3    attr_reader :response
   4    
   5    def initialize
   6      require_dependency 'application' unless defined?(ApplicationController)
   7      @controller = UserScheduleEntryController.new
   8      @request    = ActionController::TestRequest.new
   9      @response   = ActionController::TestResponse.new
  10    end
  11    
  12    def render_your_profile(user)
  13      @controller.instance_variable_set("@user", user) # bypass login required
  14      get :your_profile
  15      @response
  16    end  
  17  end
  18  
  19  test = FacebookTest.new
  20  test.render_your_profile(user)
  21  markup = test.response.body

The

   1  require_dependency
was something I threw in because backgroundrb didn't have some of the required classes loaded at that point, it may not be something you need in your application.

Comments

BN at 5:37 AM on November 14 2007

This is really awesome! Great post.

Shane at 6:14 AM on November 14 2007

I used this:

template = ERB.new(File.readlines(‘app/views/dir/my_view.rhtml’).join(’’), nil, ’-’) html = template.result(binding)

That I found here: http://whynotwiki.com/Rails

Add a comment


home | services | Ruby on Rails Development | code | blog | company