Phusion white papers Phusion overview

Rendering Rails 3.1 assets to string

By Hongli Lai on August 14th, 2011

The upcoming Rails 3.1 will come with a powerful asset pipeline, which is a framework for allowing developers to preprocess, concatenate, minify and compress Javascripts and CSS files. Javascripts can be written in CofeeScript, which is compiled on-the-fly to Javascript. Similarly, CSS can be written in Sass or SCSS, which are compiled on-the-fly to plain old CSS. Many people have already written about this topic.

Today we ran into a situation in which we wanted to render an SCSS file to a string so that we can put it in a JSON document. The way to do this is non-obvious. First try:

render :template => 'assets/stylesheets/api.css'

Rails complained that it cannot find this file in its search path, which only includes ‘app/views’.

Next try involved using the :file option because it also searches in Rails.root:

render :file => 'app/assets/stylesheets/api.css'

This time it successfully found the file, but couldn’t render it because there’s no :scss template engine. Apparently the asset pipeline does not integrate into the Rails template engine framework.

After some code digging, it turned out that asset serving is completely powered by Sprockets. The Rack middleware responsible for serving the /assets is Sprockets::Server, which looks up asset information using a Sprockets::Environment object. This object also handles rendering. The Rails integration allows such an object to be accessed through the YourApp::Application.assets method.

So the correct way to render an asset to a string is as follows:

YourApp::Application.assets.find_asset('api.css').body

Here, YourApp is your application’s module name as found in config/application.rb.

  • http://blog.der-flo.org/ der Flo

    Thanks for your solution, but there is one little bug. Compression is not applied to the resulting string. Or am I missing something?

  • Pingback: Wicked_PDF working in Rails 3.1 | Anlek Consulting

  • http://meetdom.com Dom

    Very useful information, thank you.

  • Pingback: Trevor Turk — Links for 09-26-11

  • Martin Streicher

    How do you achieve rendering outside of a controller in Rails 3.1? I have found a number of options online, but none seem to work in 3.1.

  • http://twitter.com/lenartr Lenart

    @Martin: it works for me (Rails 3.1). Make sure your file is in assets folder (/app/assets/javascripts, /app/assets/stylesheets or /app/assets/images).

  • http://irongaze.com Rob Morris

    For anyone looking to access the asset_path() helper outside of views/controllers, an easy way to do so is:

    ActionController::Base.helpers.asset_path(…)

    Useful in rake tasks, cron jobs, models, you name it.

  • http://testpilot.me Ivan Vanderbyl

    You can also simply use the Rails.application helper (in case the real ApplicationName is not available):

    Rails.application.assets.find_asset(‘api.css.scss’)

  • Pingback: Render Rails assets to string | Bi·lak

  • Adam Stankiewicz

    For me worked .soruce instead of .body (for body the requires in asset were not compiled). Cheers!

  • asgeo1

    Using .body doesn’t include any included assets, i.e. that were #= required

    I found I had to use YourApp::Application.assets.find_asset(‘api.css’).to_s or I would get an undefined method `encode' for #<Sprockets::BundledAsset" error.

    I’m probably using a later sprockets though (v2.2.2)

  • Byron Appelt

    Thank You! I have been beating my head against the wall for hours on this one.

  • Alex Plescan

    Be careful when using this with Rails 4 in production, as the string produced includes comments listing out the filepaths of your compiled assets.

    You can easily get around this by using a gsub. I use “gsub (//*.*?*//, ”)” to remove those comments from the CSS file I render.