metaduck
12Out/094

Tutorial: building and styling a Rails app with styled_objects

How to keep your stylesheets clean and organized using Rails

This tutorial covers building a web application from scratch using Rails with the styled_objects plugin.

As an example we will be building a very static front-end website, mainly to focus on stylesheets.

Everything you get from can be applied to more complex applications.

Because this is such a simple application, we won't be using scaffolding generators.

About styled_obejcts

styled_objects is a Rails plugin for simplifying stylesheet management on your application.

Instead of having one or more large stylesheets on your public folder, have many. Keep your CSS close to their respective templates. styled_objects will compile them into one file per page.

Getting started

1. Bootstrap your Rails app

$ rails testapp

2. Install the LESS gem:

Edit your config/environment.rb and place, anywhere before the "end":

config.gem 'less'

Run on the shell:

$ sudo rake gems:install

2. install the styled_objects plugin

script/plugin install git://github.com/pgte/styled_objects.git

The application

Here we will be building a simple example application for an e-commerce website.
First we will be focusing on building the controllers and the views, and finally we will learn how to style them with styled_objects.

To start we will be having products and product categories. One product can be in many categories and one category can contain many products. So, it is a many-to-many relationship.

For the sake of simplicity, let's say a product has a name and a description.

Each category have a name.

(I won't go through the building of the models, it's beyond the scope of this tutorial).

Product page

After you have your migrations and models setup, we need to configure the routes for our products controller.

Edit your config/routes.rb and add:

map.resources :products

Now build the controller under app/controllers/products_controller.rb. For now we will only have a "show" action:

class ProductsController < ApplicationController

  def show
    @product = Product.find(params[:id])
  end

end

Do the show template  under app/views/products/show.html.erb:

<h1><%= h @product.name %></h1>
<p><%= h @product.description %></p>

Category page

On this page we will be presenting all products on the current category.

Build the product category routes ou config/routes.rb:

config.resources :categories

Next, build the controller under app/controllers/categories_controller.rb:

class CategoriesController < ApplicationController

  def show
    @category = Product.find(params[:id], :include => :products)
  end

end

And the view under app/views/categories/show.html.erb:

<h1><%= h @category.name%></h1>

<p>products in this category:</p>

<%= render :partial => 'products/product', :collection => @category.products %>

This template is a bit more complex than the product show one because it presents all the products inside the current category by calling the products/_product.html.erb partial for each product.

Let's do this partial (under app/views/products/_product.html.erb):

<h2><%= link_to h(product.name), product_path(product) %></h2>
<p><%= h truncate(product.description) %></p>

Here, instead of presenting the full product description, we truncate it using the ActionView truncate helper, presenting only the first 30 characters of the product description.

Styling up

So, now that we have the category and product pages in place, we need to style them.

But first we need to style the whole website.

Global styling

Personally, I feel comfortable with using this folloing setup when starting a website, but it is not a requirement for styled_objects. (We haven't got there yet).

Reset stylesheet

There are numerous reset stylesheets out there. I particulary like the one bundled inside blueprint CSS.

So, grab a copy of blueprint and extract the blueprint/src/reset.css file and copy it into public/stylesheets/ directory.

Next, edit your app/views/layouts/application.html.erb and add the following line before the </head> tag:


<%= stylesheet_link_tag 'reset' %>

Typography sytlesheet

This is where we add a special stylesheet only for defining your typography. This is where you will be styling your p, a, ul, li, table, etc. tags.

This is your job, but I like to start from the blueprint/src/typography.css bundled on blueprint.

Save this file into public/stylesheets and add the respective the stylesheet link tag right after the reset one:

<%= stylesheet_link_tag 'reset' %>
<%= stylesheet_link_tag 'typography' %>

This stylesheet you will be formatting according to the desired look of your website.

Layout stylesheet

Before building a layout stylesheet, you need to build your layout markup. This will be done inside app/layouts/application.html.erb :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
		<title>Untitled Document</title>
		<%= javascript_include_tag 'jquery-1.3.2.min' %>
		<%= stylesheet_link_tag 'reset' %>

	</head>
	<body>
      <div class="container">
        <div id="header"><h1>Welcome to ACME</h1></div>
        <div id="main">
          <%= yield %>
        </div>
      </div>
	</body>
</html>

So, on inside our HTML body tag we have a div tag with a "container" class. This "container" class will be used to center and fix the width of our content.

This is what goes inside the layout stylesheet, under public/stylesheets/layout.css:

.container {
  width: 950px;
  margin: 0 auto;
}

So, we are setting the width of content area of our website and centering it.

A lot more could be done here, like styling the header div. This also should be done on the layout stylesheet.

The main idea here is: use the layout stylesheet to only style markup on the layout template. Don't style more than that here.

Local styling

Now we want to style our templates and partials individually. That's where styled_objects comes in.

This plugin allows you to define the styles per template or partial wiathout adding any code.

First we need to call this helper on the app/views/layouts/application.html.erb file:

<%= so_stylesheet_link_tag %>

Place it right before the </head> tag. This helper creates the link tag to the URL for the "glued" stylesheet of each page.

We now begin with the product show page.

Create app/views/products/show.css and edit it.

We want to style the title and the description:

background-color: #e0e0e0;
h1 {color: #f576d8; border-bottom: 1px solid #822321};
p {padding: 1em 0; background-color: #fff;, border-top: 1px solid #d6d6d6}

On the first line we see something that isn't pure CSS: the background color style declared on the root of the CSS document. That's there because we are styling the show.html.erb template, not any sub node.

Now we want to style the product category page.

Create app/views/categories/show.css:

border-top: 5px solid black;
background-color: #f7f7f7;
h1 {letter-spacing: -2px; color: #3e3e3e}

Here we're giving the category show template a top border (line 1), a background-color (line 2) and we're also styling the title on line 3.

This category show template also shows the products and for that it uses the products/_product.html.erb partial.

We also wish to style this partial. Create the file app/views/products/_product.css:

background-color: #999;
border: 1px solid #333;
float: left;
h2 {text-transform: uppercase}

AJAX loading

So, styled_objects collects the needed CSS fragments on each page and constructs one URL that references all the "glued" CSSes.

What if I want to have a shopping basket partial that is called by AJAX instead of normal partial rendering inside a template?

Simple: just add <%= so_include_partial(partial_path) %> (or <%= so_include_template(template_path) %> if it's a template) to anywhere on the calling template. The partial CSS will be included.

Next: See the Advanced styled_objects on Rails Tutorial

More

Read more about object-oriented CSS here:

See the presentation video:

Other resources

About Pedro Teixeira

Pedro Teixeira is a former Enterprise Java Beans technical project manager for Clarity Europe (BES Tech Ventures). On 2004 he founded a services company ( http://berro.pt ), focused on the tourism industry throughout 2005-2008, briefly worked for http://www.expedita.com, shifted to product development on 2007, rebuilt http://netmadeira.com on 2009 for ZON Madeira and currently working on lots of stuff for them. His services are available for hire.
Filed under: CSS, Rails, Web Leave a comment
Comments (4) Trackbacks (0)
  1. This is a neat idea, but I don’t know if this plugin will work for everyone from a performance perspective. It seems like it is just generating more HTTP requests and downloading a larger amount of data on the client’s end.

    Let’s say I’m working with a large, complex application, with a 10 “glued” styled_objects (which is fairly conservative, I think). If these are mixed and matched with different page loads, I could easily several dozen versions of my compiled stylsheets. Why would I make my client re-download a new complied stylesheet for every page? If you figure an average 20kb per gziped stylesheet/page. That adds up to a lot of extra overhead.

  2. Hi Mario,

    Yes, that is a concern I have: each page having a different URL, rendering another uncached HTTP request…

    But my aproach is this:
    - you should abstract as much as you can and put the bulk of your CSS onto a global stylesheet. Taking this aproach your 20K seams like a lot for the page-specific CSS…
    - you should try and reuse templates and partials as much as possible. Try to use partial layouts, etc.

    Also note that if the rendered templates are the same but on a different order, the URL will be the same.

    Having said that, the problem you presented is something I have been thinking about. There are some ways to get through it:

    - pre-generate a stylesheet containing all the glued stylesheets
    - declare stylesheet groups (template groups) that you use can later refer to.

    Any ideas?

  3. I like the concept. A few years ago I really thought I could use CSS to separate layout from ’skinning’ but that turned out to be majorly incorrect :) .

    It seems a more sophisticated approach like yours is required to achieve that holy grail.

  4. Hi Chris,

    Thanks, I have also been trying to do this for some time now, and this is mainly work in progress that I have been applying to some of my Rails projects.

    There are some edges I would like to clean out, preferably with input from others ;)

    Thanks!


Leave a comment


No trackbacks yet.