Services

Course Overview

Drawing from the real world experience of Engine Yard’s team of Ruby on Rails experts, this course provides a solid foundation in Ruby as well as Rails. Since the course is based on Rails 3.1, you will be able to take advantage of the latest features of the Rails 3 framework, such as the asset pipeline.

NOTE: THIS RAILS COURSE HAS BEEN UPDATED FOR RAILS 3.1

Prerequisites

Experience in .NET, ColdFusion, Java, Perl, PHP, or Python. Fluency in HTML and a strong understanding of Javascript.

Length: 4 days

Syllabus

Day 1 Day 2
Intro to Ruby
  1. Statements
  2. Data Types
  3. Strings
  4. Symbols
  5. Operators
  6. Classes and Instances
  7. Inheritance
  8. Modules
  9. Methods
  10. Duck Typing
  11. Blocks, Procs, and Lambdas
Discovering Rails
  1. What is Rails?
  2. Features and Limitations
  3. Web Applications 101
  4. Generating a Rails Application
Discovering Rails (cont.)
  1. Running a Rails Application
  2. A bit about Git
  3. The What and Wherefore of Git
  4. Terminology
  5. Git Clients
Models
  1. Managing Databases
  2. Models
  3. Seeds
  4. Using the Rails Console & DB Console
  5. Validating Model Data
  6. Mapping Object Relationships with Associations
  7. Queries
Day 3 Day 4
Views
  1. HAML
  2. Views
  3. Layouts
  4. Helpers
Controllers
  1. CRUD and REST
  2. Routing
  3. Controllers
  4. Filters
Formats and Forms
  1. Request formats
  2. Forms
  3. Form Helpers
Test Driven Development
  1. TDD Intro
  2. RSpec
  3. Capybara
  4. Test doubles, including mocks and stubs
  5. Factories
Cloud Deployment
  1. OpenSSH public key encryption
  2. Forking repositories
  3. Modifying source
  4. Cloud Deployment in action
Configuration and Chores
  1. Environments
  2. Rake Tasks
  3. Code Analysis

Excerpt

To give you a sense for our class, we are providing the following excerpt of Unit 5




Unit 5: Views

Unit Objectives

After completing this unit you should be able to:

  • Use ERB to create views
  • ERB versus HAML
  • Use layouts and helpers to DRY up your views
  • Understanding the Rails asset pipeline

Unit Topics

  • ERB
  • HAML
  • Views
  • Layouts
  • Helpers
  • Asset pipeline

Views

View Basics

Rails views are HTML templates which are rendered when a controller processes an action. A simple view is rendered all by itself, but it can also be wrapped in a layout and contain partial views. If a controller does not have a method defined for a particular action, it will simply look for the corresponding view template and render it. By default, views are located in a directory named after the corresponding model under app/views/

View filenames are constructed of the action name, followed by the response format, followed by the template language. A standard index view would be named index.html.erb.

Basic ERB Syntax

The default language for view templates in Rails is ERB, a templating system built in to Ruby. ERB uses a set of tags, similar to PHP or JSP, that can be interspersed with static HTML.

<% Ruby code (not displayed) %>
      	<%= Ruby expression (displayed) %>
      	<%# comment %>
      	

ERB v. Haml

ERB files consist of standard HTML and Ruby code wrapped in ERB tags. For developers accustomed to and comfortable with HTML, ERB is familiar and easy to work with. There are many alternative templating languages. Haml is one of the most popular, offering a cleaner more succinct syntax that some find easier to parse visually and efficient to write. Haml’s main distinctions are its omission of the brackets used in HTML and ERB and its use of white space to handle nesting (with all of the same controversies that Python engenders for its use of white space).

The downside to Haml is that it is not very friendly for web or graphic designers who are not familiar with the different syntax. It adds a learning curve that might not be budgeted in your project, so some prefer to stick with ERB as it nicely fits into both the Ruby and HTML world.

In this class we will use ERB since it is the default rendering engine for Rails, but we will discuss Haml as well so you can make the choice for yourself.

Haml Basics

Haml uses two spaces to indicate nesting, as a result closing tags (for markup) and end tags (for code) are not required.

ERB

<div id="profile">
      	  <div class="left column">
      	    <div id="date"><%= print_date %></div>
      	    <div id="address"><%= current_user.address %></div>
      	  </div>
      	    <div class="right column">
      	    <div id="email"><%= current_user.email %></div>
      	    <div id="bio"><%= current_user.bio %></div>
      	  </div>
      	</div>
      	

Haml

#profile
      	  .left.column
      	    #date= print_date
      	    #address= current_user.address
      	  .column
      	    #email= current_user.email
      	    #bio= current_user.bio
      	

HTML entities are prefixed with %, and HTML attributes are expressed as Ruby hashes. So, for example:

HTML:

<table border="0" cellspacing="5">
      	

HAML:

%table{:border => 0, :cellspacing => 5}
      	

Classes and IDs are expressed using the same syntax as CSS. If you omit the HTML entitiy when specifying class and/or ID information, Haml creates a div by default.

<div id="navigation" class="toolbar">

      	#navigation.toolbar
      	

Just as in ERB, = followed by a Ruby expression will be evaluated and output. Use - before Ruby code that has no output. Use -# for Haml comments.

-# A simple loop
      	%ul
      	  - @hotels.each do |hotel|
      	    %li= hotel.name
      	

Haml Gotchas

The most common Haml problems have to do with whitespace. The indent for each level of nesting must be exactly two spaces. Tabs are not allowed. Set your text editor to use “soft tabs” of exactly two spaces, and when copying and pasting, be sure your nesting is correct. The other main issue with Haml is that a single statement cannot contain any line breaks. This is intentional on the part of Haml to discourage large chunks of code in the view. There are two exceptions to the line break restriction. You can use the pipe (|) to break multiline strings, and a line break is permitted immediately after commas between attributes of an entity.

From the Haml documentation:

%whoo
      	  %hoo= h(                       |
      	    "I think this might get " +  |
      	    "pretty long so I should " + |
      	    "probably make it " +        |
      	    "multiline so it doesn't " + |
      	    "look awful.")               |
      	  %p This is short.
      	

and

%script{:type => "text/javascript",
      	        :src  => "javascripts/script_#{2 + 7}"}
      	

Walkthrough 5-1: Creating a View

In this walkthrough, you will create an index view for hotels.

Steps

  1. Generate hotels controller

    $ rails g controller hotels

  2. Create app/views/hotels/index.html.erb

    <h2>Hotels</h2>
          	<ul id="hotels">
          	  <li>Hilton</li>
          	  <li>Hyatt</li>
          	  <li>Joe's Inn</li>
          	</ul>
          	
  3. One more item is required which we have not yet had a chance to discuss, and that is a route for hotels. Insert the following line inside the main block inconfig/routes.rb. We’ll explore routes in more detail in Unit 5.

    resources :hotels

  4. View page in browser (http://localhost:3000/hotels)

Layouts

Layout Basics

Exemplifying the principle of “Don’t Repeat Yourself” which suffuses the design of Rails, layouts in Rails simplify the use of markup that is reused on multiple pages, such as HTML title and head blocks as well as application headers and footers.

Rails uses the default application layout, in our case app/views/layouts/application.html.erb since we are using Haml, unless it finds a layout specific to the model for the view being rendered. Layouts can also be disabled or overridden explicitly in the controller.

A simple layout might look as follows:

<html>
      	  <head>
      	    <title>Traveljournal</title>
      	  </head>
      	  <body>
      	    <%= yield %>
      	  </body>
      	</html>
      	

The page template being rendered will be inserted in place of the yield method. The standard Rails layout template includes a few additional items.

<!DOCTYPE html>
      	<html>
      	<head>
      	  <title>Traveljournal</title>
      	  <%= stylesheet_link_tag    "application" %>
      	  <%= javascript_include_tag "application" %>
      	  <%= csrf_meta_tags %>
      	</head>
      	<body>

      	<%= yield %>

      	</body>
      	</html>
      	

The stylesheet_include_tag and javascript_include_tag statements include the Rails default javascript files and stylesheets. The settings for these defaults can be customized or individual stylesheet and javascript files can be specified. Finally, the csrf_meta_tag statement provides protection against cross-site scripting attacks.

Walkthrough 5-2: Editing a layout

In this walkthrough, you will edit an application-wide layout.

Steps

  1. Open app/views/layouts/application.html.erb

  2. Our application template generated this template when we created the traveljournal application. Let’s edit it to make the title appear nicer.

    
          	
          	
          	
          	  Travel Journal
          	  
          	  <%= stylesheetlinktag    “application” %>
          	  <%= javascriptincludetag “application” %>
          	  <%= csrfmetatags %>
          	
          	

    <%= yield %>

  3. Open your browser and view the page.

Helpers

Helper Basics

View helpers are another way to avoid repetition in your application. Any display or formatting logic that occurs in your views can be extracted into helpers. Each model has a corresponding view helper located in /app/helpers/.

Quite simply any logic in your view can be made into a method in the view helper, which then can easily be reused, or simply used to make your views cleaner and more readable.

For example, suppose we want to display a link to flag a hotel as closed if it has closed down, or simply note that it has closed down if the link has already been clicked.

def flag_or_indicate_closed(hotel)
      	  if hotel.closed?
      	    link_to "flag as closed", close_hotel_path(hotel)
      	  else
      	    "This hotel has closed."
      	  end
      	end
      	

Take note that helpers you create in any file will be included and available to all of your views. If you wish to only include the helpers in application_helper.rb and your controller’s helper file, then call the clear_helpers method inside your ApplicationController.

class ApplicationController < ActionController::Base
      	  clear_helpers
      	  protect_from_forgery
      	end
      	

Walkthrough 5-3: Creating a Helper

In this walkthrough, you will create a simple view helper that displays the current day of the week.

Steps

  1. Edit app/helpers/hotels_helper.rb

    module HotelsHelper
          	  def day_today
          	    Date.today.strftime("%A")
          	  end
          	end
          	
  2. Add helper to view.

    <h2>Hotels as of <%= day_today %></h2>
          	<ul id="hotels">
          	  <li>Hilton</li>
          	  <li>Hyatt</li>
          	  <li>Joe's Inn</li>
          	</ul>
          	
  3. View the results in your web browser.

The Rails Asset Pipeline

In the past, Rails has relied on serving up assets by using files inside the public_html directory. All of your images, Javascript files, stylesheets, and so on would go inside this directory, to be served statically by the application. If you ever wanted to minify, compress, or obfuscate the code in your Javascript or CSS files, you’d have to rely on external tools or third-party gems. In short, it was a lot of work.

Now Rails comes with an asset pipeline, which provides a framework to concatenate, minify, and compress your Javascript and CSS assets. It also allows you to write your assets in other languages such as CoffeeScript, SCSS or SASS, and even use template languages such as ERB.

Rails uses the Sprockets library to achieve this pipeline. Previously Sprockets was available by using the sprockets-rails gem, but now it is part of the core Rails setup and enabled by default. Developers can take advantage of these features without any additional configuration.

Using the pipeline, your assets will no longer be in public_html, but instead will reside in an assets directory in one of three locations:

  • app/assets - Assets owned by the application, such as custom images, Javascript, or stylesheets. The bulk of your assets will go here.
  • lib/assets - Any assets for custom libraries or that just don’t fit into the scope of the application go here. This is useful for libraries shared across applications.
  • vendor/assets - Any assets owned by plugins, etc.

Inside your assets directory you should have a directory for images, javascripts, and stylesheets.

Concatenation

The first, although not the most exciting, feature of the pipeline is concatenation of assets. This is very important to high-traffic production applications as it lowers the number of requests for assets and thus reduces server overhead. Now the default behavior of Rails is to concatenate all assets into a single file per type (so one master Javascript file, and one master CSS document).

To concatenate all the files together, Rails uses a manifest file to determine which files to include. Each of these manifests contain directives telling Sprockets which files to require in order build the single, monolithic document. These directives come in the form of comments in the code, using one of three keywords:

  • require - includes a single document into the compiled asset output
  • require_self - Used primarily in CSS, this includes any code in the current file in the compiled asset output
  • require_tree - Similar to require, this loads all the files in the path relative to the current document.

For example, here is the default manifest for Javascripts, located in app/images/javascripts/application.js:

//= require jquery
      	//= require jquery_ujs
      	//= require_tree .
      	

The files for jquery and jquery_ujs are in Sprockets’ search path, by being part of the jquery-rails gem included by the Rails application.

For CSS documents, you see the following in app/images/stylesheets/application.css:

/*
      	 *= require_self
      	 *= require_tree .
      	 */
      	

This loads all CSS documents in app/images/stylesheets after the code in the application.css document itself. Note that the load order listed in the manifest documents is honored, so be careful when listing them.

When the documents are compiled to the single, concatenated form, Rails takes advantage of a concept called fingerprinting to add a hash to the generated filename. So long as the assets do not change, IPSs and browsers can cache the data and serve assets that way. Whenever a change is made to the assets, a new hash is generated, thus invalidating the old cache because an entirely new file will be requested.

So for example, application.css can be referenced with a hash like this: application-dd6b1cd38bfa093df600724704fd7a11.css.

Previously, rails appended a query string to the URL based on the file’s modified time, so the source looked similar to this:

/stylesheets/application.css?201107211050
      	

Each time the code is deployed or served from different machines, the potential for not honoring the cache existed. Plus, a number of web servers do not honor the query string and won’t cache the content. So it wasn’t a fool-proof method of serving up the assets and caching them.

Minification and Compression

The pipeline is also useful for minifying and compressing your asset code. This helps to save bandwidth as your files are transferred to a multitude of users, and it can also help obfuscate your Javascript code to keep the casual observer from benefiting from your hard work.

In CSS documents, this process involves removing comments and unnecessary whitespace.

In Javascript documents this gets to be more elaborate. By default Rails utilizes the uglifier gem, which is a wrapper for the UglifierJS code compressor for NodeJS. By default it will remove whitespace, mangle variable names, “squeeze” code by converting things such as if statements to ternary operations whenever possible, remove dead code that will never be executed, and more. It tightens up Javascript to make it a smaller download but it also serves to obfuscate it from prying eyes.

Preprocessing Languages

The most exciting feature of the asset pipeline has to be the ability to use other languages (or language extensions) that will be compiled down to the native Javascript and CSS code. Now, inside your Rails application you can write CSS using either SCSS or SASS, you can write CoffeeScript for Javascript, or use template languages like ERB in either.

The filenames are similarly structured to how you name views, so you have the filename, followed by the output language (js or css), and then finally use the preprocessor language as your extension. For a CoffeeScript file you would have a file named like this:

app/images/javascripts/traveljournal.js.coffee
      	

Or a CSS document like this:

app/images/stylesheets/traveljournal.css.scss
      	

One neat feature of the pipeline is the ability to stack processing. You can have a document parsed by ERB and then passed to CoffeeScript by naming it like this:

app/images/javascripts/traveljournal.js.coffee.erb
      	

The order is important. Whatever processor you list last will be processed first. So the above example will be processed by ERB first, then CoffeeScript, finally resulting in the Javascript output.

CoffeeScript

Learning the intricacies of CoffeeScript is beyond the scope of this course, but we can talk a little about what it has to offer.

CoffeeScript looks more like Ruby. You do not need semicolons to end expressions, variables do not need to be pre-declared using var, functions are specified with -> like stabby Procs, and so on.

Some examples of how it looks, taken from http://jashkenas.github.com/coffee-script :

# Assignment:
      	number   = 42
      	opposite = true

      	# Conditions:
      	number = -42 if opposite

      	# Functions:
      	square = (x) -> x * x

      	# Arrays:
      	list = [1, 2, 3, 4, 5]

      	# Objects:
      	math =
      	  root:   Math.sqrt
      	  square: square
      	  cube:   (x) -> x * square x

      	# Splats:
      	race = (winner, runners...) ->
      	  print winner, runners

      	# Existence:
      	alert "I knew it!" if elvis?

      	# Array comprehensions:
      	cubes = (math.cube num for num in list)
      	

Compiles down to this Javascript:

var cubes, list, math, num, number, opposite, race, square;
      	var __slice = Array.prototype.slice;
      	number = 42;
      	opposite = true;
      	if (opposite) {
      	  number = -42;
      	}
      	square = function(x) {
      	  return x * x;
      	};
      	list = [1, 2, 3, 4, 5];
      	math = {
      	  root: Math.sqrt,
      	  square: square,
      	  cube: function(x) {
      	    return x * square(x);
      	  }
      	};
      	race = function() {
      	  var runners, winner;
      	  winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
      	  return print(winner, runners);
      	};
      	if (typeof elvis !== "undefined" && elvis !== null) {
      	  alert("I knew it!");
      	}
      	cubes = (function() {
      	  var _i, _len, _results;
      	  _results = [];
      	  for (_i = 0, _len = list.length; _i < _len; _i++) {
      	    num = list[_i];
      	    _results.push(math.cube(num));
      	  }
      	  return _results;
      	})();
      	

SASS

SASS (Syntactically Awesome Stylesheets) was originally part of the Haml gem. It provides extensions for CSS3, such as nested rules, variables, mixins, selector inheritance, and more to your CSS documents. There are two different syntaxes you can take advantage of, but developers are leaning more toward using SCSS (Sassy CSS) as it is a superset of CSS3, meaning that valid CSS3 documents are already SCSS documents. These documents are named with a .scss extension.

The other syntax is the original SASS syntax that uses indenting rules similar to Haml as opposed to semicolons and curly braces. It is still supported if your document is named with a .sass extension.

Here is an example SCSS document that utilizes variables, mixins, and nesting:

$heading: #eee;
      	$text: #000;

      	@mixin rounded($radius:10px) {
      	  -webkit-border-radius: $radius;
      	  -moz-border-radius: $radius;
      	  border-radius: $radius;
      	}

      	header {
      	  @include rounded(5px);
      	  color: $text;
      	  background-color: $heading;
      	  a {
      	    text-decoration: underline;
      	    &:hover {
      	      text-decoration: none;
      	    }
      	  }  
      	}
      	

This generates CSS output that looks like this:

header {
      	  -webkit-border-radius: 5px;
      	  -moz-border-radius: 5px;
      	  border-radius: 5px;
      	  color: black;
      	  background-color: #eeeeee; }
      	  header a {
      	    text-decoration: underline; }
      	    header a:hover {
      	      text-decoration: none; }
      	

In this case, the generated output is smaller, but the SCSS is much more developer friendly as it contains the principles of DRY, reusable code, and better object-oriented concepts than base CSS can offer.

Unit Review

  • Views
  • ERB
  • Haml
  • Layouts
  • Helpers

Lab 5: Creating views, layouts, & helpers

In this lab you will create two views for trips, an application layout, and a view helper for trips.

Objectives

After completing this lab you should be able to:

  • Create views using ERB
  • Create layouts
  • Create partials
  • Create view helpers

Steps

Create an index view

  1. Generate a controller for trips.
  2. Update routes
  3. Create an index view.
  4. View page in browser.

Create a Partial

Partial templates are reusable view templates that can be called by other templates in order to further DRY up your code, similar to how helper methods are used.

To create a partial template, create a normal template but start the filename with an underscore character.

  1. To create a partial template the application layout will look for and render, we will need to create a directory named app/views/application, which will be in the layout search path for rendering the partial, regardless of which controller we are using:

    $ mkdir app/views/application
          	
  2. Write a partial template to add a Tweet button to the page in app/views/application/_tweet.html.erb. The code for building a button can be found on http://twitter.com/about/resources/tweetbutton or you can use the following pre-defined snippet:

    <a href="http://twitter.com/share" class="twitter-share-button"·
          	  data-text="I am taking the Zero to Rails 3 Course right now #eyu"·
          	  data-count="horizontal"·
          	  data-url="http://www.engineyard.com/university"·
          	  data-via="eyuniversity">Tweet</a>
          	<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
          	
  3. Add the partial to app/views/layouts/application.html.erb with the following line, right above the line calling yield:

    <%= render "tweet" %>
          	
  4. Reload the page and watch the Tweet button appear!

Create a helper

  1. Let’s create a helper method that will display a Gravatar for a user’s e-mail address. More info is available at: http://en.gravatar.com/
  2. Edit the file app/helpers/hotels_helper.rb
  3. Add this method:

    def gravatar(email)
          	  require "digest/md5"
          	  hash = Digest::MD5.hexdigest(email)
          	  "http://www.gravatar.com/avatar/#{hash}?s=32"
          	end
          	
  4. Back in the application layout, add this line right above the call to render the tweet partial. Use your email address if you have a Gravatar image setup already:

    <%= image_tag gravatar("tgourley@engineyard.com") %>
          	
  5. Verify that everything looks as expected in browser