Ruby-on-rails – How does one reference compiled assets from the controller in Rails 3.1

asset-pipelineruby-on-railsruby-on-rails-3.1

I'm using the PDFkit in my controller to build out a series of PDFs, zip them up, and then send them to the user.

In order to control the output styles, I tell PDFKit which stylesheets to use during content generation. I need to pass along the file reference of the CSS file. Since Rails is now compiling and renaming my stylesheets, I'm not sure how to reference the compiled CSS asset inside my controller.

Here's what I used to do:

InvoicesController < ApplicationController
  def download
    kit = PDFKit.new(render_to_string(:show, :layout => false))
    kit.stylesheets << "#{Sass::Plugin.options[:css_location]}/application.css"
    kit.to_file("#{file_date_string}.pdf")
    # snip
  end
end

Sass::Plugin.options[:css_location] now returns the incorrect location, not to mention the fact that application.css is no longer the valid name of the file. I should mention that I have an app/assets/application.css file that serves as a manifest for my SCSS files, and it is working correctly in my views via the stylesheet_link_tag() method.

Basically what I'm looking for is a controller equivalent of asset_path() in order to do something like this:

kit = PDFKit.new(render_to_string(:show, :layout => false))
kit.stylesheets << asset_path('application.css')
kit.to_file("#{file_date_string}.pdf")

Can anyone help?

Best Answer

Rails.application.assets is poorly documented but it provides access to Rails' hook into Sprockets, as a Sprockets::Environment object. Rails uses Sprockets to basically run the whole asset pipeline, and this is where you should hook in for things like this:

kit.stylesheets << Rails.application.assets['application.css'].pathname

https://github.com/sstephenson/sprockets says of it:

Accessing Assets Programmatically

You can use the find_asset method (aliased as []) to retrieve an asset from a Sprockets environment. Pass it a logical path and you'll get a Sprockets::BundledAsset instance back:

  environment['application.js']
  # => #<Sprockets::BundledAsset ...>

Call to_s on the resulting asset to access its contents, length to get its length in bytes, mtime to query its last-modified time, and pathname to get its full path on the filesystem.