Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
A Gem to allow CSS views in Rails
Ruby
branch: master
Failed to load latest commit information.
lib update version in module
test Update gem name to CSS Views
LICENSE Add Radio NZ copyright to license
README.rdoc
Rakefile Add default task to Rakefile
css_views.gemspec

README.rdoc

CSS Views

NOTE: This code has been made redundant by the introduction of the asset pipeline in Rails 3.1 This means that the code won't be maintained anymore, and will probably break sometime in the future.

:-(

This gem is designed to provide CSS views to Rails, and a process to concatenate and minify these files to one file for production.

In development mode the specified css views also are processed and served as one file, but the source can still be updated and the changes viewed without restarting the server.

This allows you to see the full effect of the production packaging in development, avoiding any post-deployment surprises.

The Gem uses Rails internal APIs to minimise code and provide a terse interface.

NB: While you can use Ruby (and Rails) constructs in your css.erb files, these are evaluated ONCE ONLY on the first production request after deployment. This means you cannot use dynamic run-time variables in the css.erb files (e.g. for session based information)

Also, this library only concatenates the resultant files. It does not minify, see

Background

The idea for this Gem came from DHH's RailsConf 2010 keynote:

www.youtube.com/watch?v=b0iKYRKtAsA

About 33 minutes in he talks about /public being a junk drawer and perhaps some of the stuff could be moved into app/, giving us huge benefits. Having CSS views (and javascript views) allows us to do other stuff with the contents of those files.

For example, smaller images included in the CSS could be turned into data urls inside the file to save http requests. Minifiers/JS reduction can also me used.

Patches are welcome, however keep in mind the aim of this gem: to be as simple as possible and cover the majority of use-cases.

Radio New Zealand funded this code for use on our internal (and public) projects and we are releasing it under a free software license.

Setup

Views

Create a views folder and put your stylesheets in it:

+ stylesheets
     + reset.css.erb
     + layout.css.erb
     + branding.css.erb

The CSS files can reference images (via image_tag), and expand out ruby variables that may be set elsewhere.

This means that any images inside the CSS use whatever cache busting scheme you've specified in Rails.

Controller

(app/controllers/stylesheets.rb)

The controller requires the Gem, and includes the module:

require 'css_views'

class StylesheetsController < ApplicationController
  include CssViews::ControllerMixins

  css_configuration 'application', :components => ['reset', 'layout', 'colors'], :transformers => [Minifier.new]
end

The configuration takes:

1. The name you want to give the file in production (this is the :configutation_name in the route below)
2. An array of views in the order you want to combine them
3. Optionally, an instance of a Class (or an Array of them) transform the assembled CSS views.

Each transformer must have a method called transform that takes and return a string

class Minifier
  def transform(css)
    do something here
    return the result
  end
end

If more than one is included, the CSS is transformed by each in the order specified.

You can have as many css_configurations as you need.

If you want to setup ruby variables to use in the CSS views, then use a before filter:

before_filter :set_vars

and later in the stylsheet_controller

private

def set_vars
  # your stuff here
end

Route

The route in routes.rb can take two forms.

  1. The standard route:

match '/stylesheets/:configuration_name(.:format)' => "stylesheets#show", :as=>:packaged_stylesheet
  1. The cache-busting route:

match '/stylesheets/:cache_buster/:configuration_name(.:format)' => "stylesheets#show", :as=>:packaged_stylesheet

This will allow an additional parameter that can be changed for each deployment.

When this param is set, the Gem sets the Expires and Public cache control headers for the first request made. It is up to you to set these header in your webserver's config to cater for subsequent requests.

See asset_tag_helper.rb in the Rails source for more information on cache-busting and setting up Apache.

NB: You can also do:

match '/stylesheets/:configuration_name-:cache_buster(.:format)' => "stylesheets#show", :as=>:packaged_stylesheet

if you want the cache busting string embedded in the filename.

Application.html.erb

The route provides a path helper - packaged_stylesheet_path.

This:

packaged_stylesheet_path(CacheBusterFunction, 'global', :css)

generates a link to global.css which is handled by the show method.

CacheBusterFunction is something that return a string to use as the cache buster

Use this if you use the embedded route syntax:

packaged_stylesheet_path('global', CacheBusterFunction, :css)

The rendered file is subject to normal rails caching rules:

  1. It is not cached in development, but uses etags so unless the source in the CSS views is modified the

browser will get a 304 back.

  1. Is cached in production after the first request.

CacheBusterFunction could just return text. For example the current CSS version number.

Using a version number would mean that the CSS file name stays the same across deployments, which is more efficient than using mtime (clients would not have to download it needlessly). Mtime is going to change with every deployment, even if the CSS content does not change, because each deployment (via capistrano/svn/git uses new files each time (with new mtimes).

NB: A rewrite rule is NOT required for the CSS file generated this way, as is needed with other cachebusting schemes.

You should set up far-future headers in Apache though.

Example Controller

This is an example of the controller from radionz.co.nz

The transformer class is a container for the css_toolkit yui_compressor function.

This allows us to check in development that the minification does not break the sites design.

require 'css_views'
require 'css_toolkit'

class Transformer
  include CssToolkit
  def transform(css)
    yui_compressor(css)
  end
end

class StylesheetsController < ApplicationController
  include CssViews::ControllerMixins

  before_filter :set_vars

  css_configuration "application", :components=>['global', 'application', 'print'],:transformers=>[Transformer.new]

  private
  def set_vars
    @corp_black = '#310C04'
  end
end

Note on using Etags

If you use the cache buster, you should set Etags on in Apache.

To match the Rails method of calculation use this in Apache

FileETag MTime

(httpd.apache.org/docs/2.0/mod/core.html#fileetag)

Something went wrong with that request. Please try again.