If - for whatever reason - you have to render stylesheets dynamically, the following snippet might be of help. It emulates what "sprockets" would to when precompiling your assets, and give your stylesheets access to all the regular bells and whistles (like asset_path
, proper @import
s etc):
class DynamicStylesheetsController < ApplicationController
def show
logical_path = RELATIVE_PATH_TO_YOUR_TEMPLATE
path = File.join(Rails.root, logical_path)
template = Sass::Rails::SassTemplate.new(path)
environment = YourApp::Application.assets
context = environment.context_class.new(environment, logical_path, Pathname.new(path))
output = template.render(context)
render :text => output, :content_type => 'text/css'
end
end
I needed to inject some color values into my stylesheets, and did not want to run everything through ERB first (which is also hard, because of @import statements etc). So I did basically this:
Before the template.render
, insert:
context.singleton_class.send(:define_method, :theme_colors) do
HASH_OF_COLOR_VALUES # e.g. { 'primary' => [100, 250, 10] }
end
In an initializer, add
module Sass::Script::Functions
def color(color_name)
assert_type color_name, :String
context = @options[:custom][:resolver].context
Sass::Script::Color.new(context.theme_colors[color_name.to_s])
end
declare :color, :args => [:string]
end
In your sass template, use something like
$PRIMARY_COLOR = color(primary)
Sass is not especially fast (and it usually does not have to be). For my medium-sized stylesheet, rendering took about 0.5 seconds. It's probably still a good idea to
This solution is probably somewhat brittle, since the methods used are not exactly part of a public API. If you know of a cleaner way to do this, please drop me a line.