Ruby on Rails, Part 1

LUG Programming Course, 10th March 2008
This week's lesson starts us on a two part adventure building a web application using Ruby and the Ruby on Rails framework. You'll need to install Ruby on Rails – we're using version 2.0.2. Our application also uses RMagick and SQLite. Installing RMagick is explained in this FAQ, we're using version 2.0.0. Installing SQLite is explained in this How-to, we're using the Ruby SQLite3 wrapper version 1.2.1. Windows users will need both the .exe and .dll versions of SQLite. The Ruby on Rails Wiki page also gives helpful information for SQLite.
The lesson went quite well, and although there was a lot to cover, we overran by only 15 minutes.

The WebAlbum Application

We'll build a web application for multiple users which allows then to upload images into albums. What? It's already been done? Well I'll admit this isn't going to get Flickr worried, but it will demonstrate many aspects of the Ruby on Rails framework.
The application will allow any visitor to register themselves as a user. Then they can create unlimited numbers of albums, each with unlimited numbers of pictures. Users can edit and modify their own albums and pictures. Logged in users see only their own albums and pictures. Anonymous visitors can see all the users, their albums and pictures.
The Real World
I admit that these specifications are not very realistic. You'd probably also want private albums and pictures, which you'd then allow a few chosen family members and friends to see. We simply won't have the time in two lessons to do that, but you're welcome to extend the application yourself.
Reality Check
Have you noticed that we always manage to specify the program in just a couple of paragraphs? You've probably already developed some mental picture of how it's going to work, you can see the list of albums, you're already clicking on them to see the list of thumbnail pictures, choosing one, and then seeing it full screen.
All that in just 30 seconds. Unfortunately, we need to convert that mental image into a program, and even Ruby on Rails can't read minds. Those 30 seconds are going to translate into at least 4 hours of work.
This is the classic client / developer impedance mismatch. You, the client, are thinking “instant”, whereas we, the developers, are thinking “half a day's work”. The other problem is that the client's mental image may also be very different from the developer's. That can lead to nasty surprises.
Since this application is going to take more than one lesson to explain, we'll use the “release early and often” open source solution. We won't be able to finish the application this week, but we'll leave the fictitious client something to “play with” at the end of the lesson. It may not look marvellous, but it'll work.
Using Rails Generators
Rails comes with a suite of code generators which prepare the way for our own efforts. The first we'll look at is the basic application generator called rails. It creates much of the boilerplate code, including the three 'classic' environments test, development and production, and prepares the database.
As always, there is an archived file at the end of this discussion, containing all the code for the lesson. What follows here is an explanation of how we get to produce that code. Do try to build the application yourself, you'll find it helps in the learning process.
So, let's get going. Create a folder for the project (mine is /Courses/LUGPC9, but you can choose any name you like). Open a console in that folder and type:
rails WebAlbum --database=sqlite3
What you should see in the console is:
C:\Courses\LUGPC9>rails WebAlbum -–database=sqlite3
      create  app/controllers
      create  app/helpers
      create  app/models
      create  app/views/layouts
      create  config/environments
      create  config/initializers
      create  db
      create  doc
      create  lib
      create  lib/tasks
      create  log
      create  public/images
      create  public/javascripts
      create  public/stylesheets
      create  script/performance
      create  script/process
      create  test/fixtures
      create  test/functional
      create  test/integration
      create  test/mocks/development
      create  test/mocks/test
      create  test/unit
      create  vendor
      create  vendor/plugins
      create  tmp/sessions
      create  tmp/sockets
      create  tmp/cache
      create  tmp/pids
      create  Rakefile
      create  README
      create  app/controllers/application.rb
      create  app/helpers/application_helper.rb
      create  test/test_helper.rb
      create  config/database.yml
      create  config/routes.rb
      create  public/.htaccess
      create  config/initializers/inflections.rb
      create  config/initializers/mime_types.rb
      create  config/boot.rb
      create  config/environment.rb
      create  config/environments/production.rb
      create  config/environments/development.rb
      create  config/environments/test.rb
      create  script/about
      create  script/console
      create  script/destroy
      create  script/generate
      create  script/performance/benchmarker
      create  script/performance/profiler
      create  script/performance/request
      create  script/process/reaper
      create  script/process/spawner
      create  script/process/inspector
      create  script/runner
      create  script/server
      create  script/plugin
      create  public/dispatch.rb
      create  public/dispatch.cgi
      create  public/dispatch.fcgi
      create  public/404.html
      create  public/422.html
      create  public/500.html
      create  public/index.html
      create  public/favicon.ico
      create  public/robots.txt
      create  public/images/rails.png
      create  public/javascripts/prototype.js
      create  public/javascripts/effects.js
      create  public/javascripts/dragdrop.js
      create  public/javascripts/controls.js
      create  public/javascripts/application.js
      create  doc/README_FOR_APP
      create  log/server.log
      create  log/production.log
      create  log/development.log
      create  log/test.log
Keep calm. All those files might look frightening, but for the time being we're only interested in three of the folders; app - where we put our web application code, public – where we put our static files, and db – where the database lives.
Now make WebAlbum the current folder in your console. All further console work is going to take place exclusively inside WebAlbum.
Although we're using the latest version of Rails, it is a fast moving target. Newer versions may break our code, so we want to keep a local copy of Rails right in our application. We do that with the freeze command:
rake rails:freeze:gems
The output will look something like:
C:\Courses\LUGPC9\WebAlbum>rake rails:freeze:gems
(in C:/Courses/LUGPC9/WebAlbum)
Freezing to the gems for Rails 2.0.2
Unpacked gem: 'activesupport-2.0.2'
Unpacked gem: 'activerecord-2.0.2'
Unpacked gem: 'actionpack-2.0.2'
Unpacked gem: 'actionmailer-2.0.2'
Unpacked gem: 'activeresource-2.0.2'
Unpacked gem: 'rails-2.0.2'
Now our application will use the Rails code (in the vendor folder), and not the Rails code in our Ruby distribution. Next we'll check that the database settings are working. Type:
rake db:migrate
The output should be:
C:\Courses\LUGPC9\WebAlbum>rake db:migrate
(in C:/Courses/LUGPC9/WebAlbum)
The db folder will now contain two files:
So far, so good. The next step is to generate the scaffolding code for our users. We'll start off with just a couple of fields, we'll add additional fields in a moment. Type:
ruby script/generate scaffold user name:string motto:string
The output will look something like:
C:\Courses\LUGPC9\WebAlbum>ruby script/generate scaffold user name:string motto:string
      exists  app/models/
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/users
      exists  app/views/layouts/
      exists  test/functional/
      exists  test/unit/
      create  app/views/users/index.html.erb
      create  app/views/users/show.html.erb
      create  app/views/users/new.html.erb
      create  app/views/users/edit.html.erb
      create  app/views/layouts/users.html.erb
      create  public/stylesheets/scaffold.css
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
      create    app/models/user.rb
      create    test/unit/user_test.rb
      create    test/fixtures/users.yml
      create    db/migrate
      create    db/migrate/001_create_users.rb
      create  app/controllers/users_controller.rb
      create  test/functional/users_controller_test.rb
      create  app/helpers/users_helper.rb
       route  map.resources :users
Again, please stay seated, the Captain has everything under control – I hope. Forget the exists messages and look at the create messages. Rails created a controller - app/controllers/users_controller.rb, a model app/models/user.rb, and four views for our user - app/views/users/*.html.erb. The model-view-controller pattern is used by Rails, and most other web application frameworks, to distribute the work. The model takes care of the data, the view handles displaying information, and the controller coordinates the whole thing.
Rails also created a database migrate class - db/migrate/001_create_users.rb. This class inherits from ActiveRecord::Migration which provides methods to change the database structure. We need a few more fields than we defined in the scaffold script, so open this file, and modify it to look like:
class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :name, :limit => 40, :null => false
      t.string :motto, :limit => 80
      t.string :salted_password, :limit => 40, :null => false
      t.string :salt, :limit => 40, :null => false
    add_index :users, [:name], :name => :users_name_index, :unique => true

  def self.down
    remove_index :users, :name => :users_name_index
    drop_table :users
I've highlighted the modifications so that you can see the changes from the original file. ActiveRecord::Migration is Rails' way of version controlling the database. We can keep modifying the database, adding new migration files, and Rails will keep track of it all. If we make a mistake, we can usually retrace our steps by reverting to a previous version, and carry on from there. Our CreateUsers class has two class methods (that's why they start with self), up adds the modifications to the database from the previous version, and down reverts the database to the previous version. - it undoes whatever up did, usually in reverse order.
Our up method creates the users database table, and a database index for the user name. The down method removes the index and then the table, in that order. Our users can have a name and a motto (something like “I am the greatest”, if you're Mohammed Ali). I'll talk about the salt stuff a little later.
Right now we're at version 0, so let's update the database. Type:
rake db:migrate
The output will be similar to the following:
C:\Courses\LUGPC9\WebAlbum>rake db:migrate
(in C:/Courses/LUGPC9/WebAlbum)
== 1 CreateUsers: migrating ===================================================
-- create_table(:users)
   -> 0.0940s
-- add_index("users", [:name], {:name=>:users_name_index, :unique=>true})
   -> 0.2500s
== 1 CreateUsers: migrated (0.3440s) ==========================================
If you want to check that you can revert to the previous version, then add the version number to the rake command:
rake db:migrate VERSION=0
The output will be similar to the following:
C:\Courses\LUGPC9\WebAlbum>rake db:migrate VERSION=0
(in C:/Courses/LUGPC9/WebAlbum)
== 1 CreateUsers: reverting ===================================================
-- remove_index(:users, {:name=>:users_name_index})
   -> 0.0620s
-- drop_table(:users)
   -> 0.0780s
== 1 CreateUsers: reverted (0.1400s) ==========================================
Remember to run rake again without the version number afterwards.
Now let's take a look at what we've got. Start the web application, by typing:
ruby script/server
The output will be as follows:
C:\Courses\LUGPC9\WebAlbum>ruby script/server
=> Booting WEBrick...
=> Rails application started on
=> Ctrl-C to shutdown server; call with --help for options
[2008-02-22 10:11:21] INFO  WEBrick 1.3.1
[2008-02-22 10:11:21] INFO  ruby 1.8.6 (2007-09-24) [i386-mswin32]
[2008-02-22 10:11:21] INFO  WEBrick::HTTPServer#start: pid=3124 port=3000
Start up your favourite browser, and type http://localhost:3000/ in the location bar. When the Rails home page appears, click on the “About your application's environment” link, see below.
Now lets look at what Rails prepared for us as our users views. Add users to the location, and load the page.
Not too exciting, because we haven't actually got any users yet, however Rails provides a lot of boilerplate code for us. The next step will be to allow us to create a new user. What? You want to click on the “New user” link? Alright, but don't try to create a new user - we aren't quite ready for that.
Now shut down the server (Ctrl+C), we've got some more coding to do.
Our First User
Each of our users will have a password. We don't want to keep that password as plain text, because, well, someone might steal it. I'm not talking about stealing a single user's password, I'm talking about the whole database. The 'salt and shaker' process used here is probably a good enough solution to a potentially big problem. Ranting aside, let's look at the code. This is the modified app/models/user.rb file:
require 'digest/sha1'

class User < ActiveRecord::Base
  attr_readonly :name
  attr_reader   :password
  attr_accessor :password_confirmation

  validates_presence_of   :name
  validates_length_of     :name, :within => 1..40
  validates_uniqueness_of :name

  validates_length_of     :motto, :within => 0..80

  validates_confirmation_of :password

  def password=(pword)
    @password = pword.strip
    return if @password.length < 6 || @password.length > 40
    self.salt = Digest::SHA1.hexdigest("--#{}--#{rand.to_s}--")
    self.salted_password = User.encrypted_password(self.salt, @password)

  def validate_on_create
    if @password.length < 6 || @password.length > 40
      errors.add(:password, "must have between 6 and 40 characters")

  def self.authenticate(name, password)
    user = find(:first, :conditions => [ "name = ?", name ])
    if user
      if user.salted_password != encrypted_password(user.salt, password)
        user = nil

    def self.encrypted_password(salt, password)
ActiveRecord::Base is just bristling with methods, including those found in ActiveRecord::Validations. Errors are handled by an instance of the ActiveRecord::Errors class, called errors. We use attr_readonly to make the name field a constant, because we don't want the user changing his user name.
The validates_* methods will do all the checking for us, including confirming that password is the same as password_confirmation (we'll ask for the password twice to ensure that the user doesn't make a typing mishtake). In the form we'll ask for a field called password, which we'll actually store in the database field salted_password, using the password= method. The validate_on_create method makes sure that a password is given when we attempt to create a new user. The class method authenticate is used when the user attempts to log in to our application. The private class method encrypted_password is used to calculate the, uhm, encrypted password.
Now we'll need to make some modifications to the ERB template for a new user, in the file app/views/user/new.html.erb:
<h1>New user</h1>

<%= error_messages_for :user %>

<% form_for(@user) do |f| %>
    <%= f.label :name, 'Name:' %>
    <%= f.text_field :name, :size =>40, :maxlength => 40 %>

    <%= f.label :motto, 'Motto:' %>
    <%= f.text_field :motto, :size => 40, :maxlength => 80 %>

    <%= f.label :password, 'Password:' %>
    <%= f.password_field :password, :size => 40, :maxlength => 40 %>

    <%= f.label :password_confirmation, 'Confirm password:' %>
    <%= f.password_field :password_confirmation, :size => 40, :maxlength => 40 %>

    <%= f.submit "Create" %>
<% end %>

<%= link_to 'Back', users_path %>
Here we've just added the two fields for password, and password_confirmation, and added a few attributes. We've also used <div> elements instead of <p>, and replaced the <b>...</b> elements with f.label helper method calls.
Now we're ready to add a user. Fire up the server again:
ruby script/server
Open the browser and go to the location http://localhost:3000/users/new. You should now see something like this:
Now I know you're just dying to create a user, but try submitting the empty form first. You should see something like this:
Seems like most of the validation is working. Hmm, pity that Rails modified our formatting though. Now fill in the name, the motto (if you want to), the password, but not the password_confirmation:
Well, confirmation validation works as well. At this point, let's really create the user (add the password in the confirm password field):
Now ain't that grand? We've created a user, and we also get a nice green message telling us so. Now we can go back to the index page and see how that looks:
What if we want to edit the user properties? That page now looks like:
Hmm, there's work to be done here as well. Certainly the Rails generators have done much of the groundwork for us, but there is still much that can be done to improve things. Scaffolding code should be considered just that - an initial platform on which we construct our own application.
The app/views/users/show.html.erb template needs modifying so that we can have better CSS control over the positioning of the elements:
<h1>Showing user</h1>

<div class='show'>
  <p class='label'>Name:</p>
  <p class='value'><%=h %></p>

<div class='show'>
  <p class='label'>Motto:</p>
  <p class='value'><%=h @user.motto %></p>

<div class='show'>
  <% if same_user? @user %>
    <%= link_to 'Edit', edit_user_path(@user) %> |
  <% end %>
  <%= link_to 'Back', users_path %>
As a security measure, we've wrapped the link to the edit page with a test that the logged in user is the user being displayed, same_user?. This is explained in a moment.
The same applies for the app/views/users/edit.html.erb template, which needs similar modifications to those we made for the new user form:
<h1>Editing user</h1>

<% if same_user? @user %>

  <%= error_messages_for :user %>

  <% form_for(@user) do |f| %>
      <%= f.label :name, 'Name:' %>
      <%= f.text_field :name, :size => 40, :maxlength => 40,
            :disabled => 'disabled', :class => 'disabled' %>

      <%= f.label :motto, 'Motto:' %>
      <%= f.text_field :motto, :size => 40, :maxlength => 80 %>

      <%= f.submit "Update" %>
  <% end %>

<% else %>

  <p class='advise'>
    You must be logged in to change this information.

<% end %>

<%= link_to 'Show', @user %> |
<%= link_to 'Back', users_path %>
This time we skip the entire form if it's not the same_user?, and display an advisory message. Although we display the user name as a text_field, we've also set the disabled flag, so that it can't be modified.
In the user list page, app/views/users/index.html.erb, the New user link is at the bottom of the page. As the user list grows, we'll have to scroll down to the bottom to create a new user. We can remedy this by repeating the link at the top of the page:
<h1>Listing users</h1>

<%= link_to 'New user', new_user_path %>



<% for user in @users %>
    <td><%=h %></td>
    <td><%=h user.motto %></td>
    <td><%= link_to 'Show', user %></td>
    <% if same_user? user %>
      <td><%= link_to 'Edit', edit_user_path(user) %></td>
    <% end %>
<% end %>


<%= link_to 'New user', new_user_path %>
We also removed the Destroy link, and wrapped the Edit link as for previous pages. Now shut down the server again (Ctrl+C).
You might be interested in seeing what's inside the database, so at the console, type:
sqlite3 db/development.sqlite3
You should see something like:
C:\Courses\LUGPC9\WebAlbum>sqlite3 db/development.sqlite3
SQLite version 3.5.6
Enter “.help” for instructions
First, let's see what tables we have in the database:
sqlite> .tables
which gives:
schema_info  users
The schema_info table is created by Rails. It contains the current migration version number. The second table contains our users, all one of them. Let's have a look at the table contents, type:
sqlite> .header ON
sqlite> select * from schema_info;
which gives:
The select... line is an SQL query – actually probably one of the simplest there is. It translates to “select and get all the columns in the schema_info table for all the rows”.
Now let's look at the users table:
sqlite> select * from users;
which gives:
1|jhl|I'm part of the Villafranca LUG team|
2008-02-29 18:39:05|2008-02-29 18:39:05
I tidied the last output up a bit because of the 80 column line wrapping. I'm not too worried that you'll be able to understand my password. Now type:
sqlite> .exit
to leave the SQLite console.
You can achieve the same results using the Rails console. Type
ruby script/console
Then when the console prompt appears, type User.find :all, the results will look like:
C:\Courses\LUGPC9\WebAlbum>ruby script/console
Loading development environment (Rails 2.0.2)
>> User.find :all
=> [#<User id: 1, name: "jhl", motto: "I'm part of the Villafranca LUG team", sa
lted_password: "56352147b463894ee939eb92c5842f5cbc223a9f", salt: "df6480b74d7814
c2a51375883f544ef7044d3bd4", created_at: "2008-02-22 18:39:05", updated_at: "200
8-02-22 18:39:05">]
>> quit
Remember to type quit to exit the console.

Pause for Thought

Before we can consider the application ready for an 'early' release, we still have the following tasks to complete:
  • We need to make the pages look better.
  • The error highlighting in the form changes the layout of the form itself, which needs correcting.
  • The user must be able to log in and out.
  • Only the specific user can edit their own information.
You've probably noticed by now that the templates we've looked at are actually only a fragment of the entire page. In app/views/layouts you'll find a template called users.html.erb. It contains the body of the HTML page, and a yield statement, which passes control to one of our templates. Rails makes great use of such 'partial' templates to reduce the amount of code, and avoid repeated code – which would be worse. We can use this knowledge to make our own 'application wide' layout, complete with header and footer, which well see in a moment.
We'd like to change the Rails standard behaviour when highlighting fields with errors, because it currently breaks the layout of our forms. Rails wraps a <div class='fieldWithErrors'> around the offending <label> and <input> elements – I checked using Firebug in Firefox. How do we find the code that does this work? Well, I didn't know either, so I did a file search for the class name fieldWithErrors, which gave back this code snippet from vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb:
module ActionView
  class Base
    @@field_error_proc ={ |html_tag, instance|
      "<div class=\"fieldWithErrors\">#{html_tag}</div>" }
    cattr_accessor :field_error_proc
Hmm, so if we give a different Proc object to the class variable ActionView::Base.field_error_proc then we can change the behaviour. Good.
Since we can now create users, we need to be able to log them in and out. As you may already know, HTTP is a stateless protocol, which means that once the server has responded to a browser request, it forgets the whole deal. But now we need to keep the information about the logged in user between multiple requests and responses. Well, you'll be glad to know that it can be done – using cookies on the browser and sessions on the server. All clever stuff which Rails handles transparently for us. Here is the cookie for our little application:
It uses the application name, and an encrypted value, which Rails will associate on the server side with the session object. So all we need to do is store the user (or better, the user's identifier) in the session object.
Now that we've got the groundwork out of the way, we can get back to coding.
The Master Layout Template
As a starting point for improving the web pages, we'll create a master page template. In app/views/layouts rename user.html.erb to web_album.html.erb. Now we'll modify our layout template:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="" xml:lang="en" lang="en">
    <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
    <% title = 'WebAlbum: ' +
         controller.controller_name.capitalize + ': ' +
         controller.action_name.capitalize %>
    <title><%= title %></title>
    <%= stylesheet_link_tag 'web_album' %>
<%= render 'layouts/partials/header' %>
    <div class='content'>
      <p style="color: green"><%= flash[:notice] %></p>
<%= yield  %>
<%= render 'layouts/partials/footer' %>
I've highlighted the changes. We calculate the title, using Rails methods, based on the controller name and action. We use the render method to, uhm, render the two partial templates, header and footer, which we'll look at next.
In app/views/layouts we'll create a /partials folder for our header and footer templates. Here is header.html.erb:
<div class='header'>
  <div class='title'>WebAlbum</div>
  <div class='login_form'>
    <% logged_user = current_user
       form_tag "/#{controller.controller_name}/#{logged_user ? 'logout' : 'login'}" do %>
      <p class='login'>
        <% if logged_user %>
          User: <span class='user'><%= link_to, logged_user %></span>
          <%= submit_tag 'Log out' %>
        <% else %>
          Name: <%= text_field_tag :name, params[:name], :size => 15, :maxlength => 40 %>
          Password: <%= password_field_tag :password, params[:password], :size => 15,
            :maxlength => 40 %>
          <%= hidden_field_tag :url, url_for %>
          <%= submit_tag 'Log in' %>
        <% end %>
      <p class='login_notice'><%= flash[:login_notice] %></p>
    <% end %>
The lion's share of the code here handles the log in (and out) form. It uses the current_user method, explained in a moment, to check if a user is already logged in. If so, the user's name (linked to their user edit page) and the log out button is shown. If not, then the usual name/password form is shown. This form is available on every page, so we use the controller's name, and two actions; login and logout.
This is the brief footer.html.erb:
<div class='footer'>
  <p>WebAlbum. Brought to you by the Villafranca LUG team.</p>
We've changed the CSS file name in the template, so we'll have to do the same in public/stylesheets. Rename scaffold.css to web_album.css. The modified CSS file contents can be found in the downloadable archive as it is a little too large to list here.
Controllers and Helpers
We still have a few minor modifications to make to our Ruby code, before we've completed the tasks for this lesson. We need to write the login and logout action methods, we need to tell the users_controller.rb which layout template to use, and we need to change the error procedure we talked about before.
Since all our controllers inherit from ApplicationController in app/controllers/application.rb, this is were we'll put our action methods:
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.

class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time

  # See ActionController::RequestForgeryProtection for details
  # Uncomment the :secret if you're not using the cookie session store
  protect_from_forgery # :secret => 'de30b92a0dfd2a772c000dee4ea91d09'

  def login
    session[:user_id] = nil
      user = User.authenticate(params[:name], params[:password])
      if user
        session[:user_id] =
        flash[:login_notice] = "Invalid name/password combination"
      redirect_to params[:url]
      redirect_to '/users'

  def logout
    session[:user_id] = nil
    redirect_to '/users'

  helper_method :find_user
  def find_user(id)
    User.find(:first, :conditions => [ "id = ?", id ])

  helper_method :current_user
  def current_user
    @current_user ||= (session[:user_id] ? find_user(session[:user_id]) : nil)

  helper_method :same_user?
  def same_user?(user)
    logged_user = current_user
    return true if logged_user && ==
When a user attempts to log in, we check the authenticity, and if successful set the session user_id. If unsuccessful, we show an error message, and reload the current page (which was stored in the form as a hidden field). The worst case situation is if no form was posted at all, in this case we redirect to the users list page.
We've also put the current_user and same_user methods here, and marked them both as a helper_method for the view templates, rather than being an action method.
In app/controllers/users_controller.rb we'll add layout 'web_album' to the start of the class definition, so that it uses our master template, instead of the default. The file now begins like this:
class UsersController < ApplicationController
  layout 'web_album'
One further small modification to this file is to automatically login a newly created user. This means adding a single line of code to the create method:
def create
  @user =[:user])

  respond_to do |format|
      session[:user_id] =
      flash[:notice] = 'User was successfully created.'
      format.html { redirect_to(@user) }
      format.xml  { render :xml => @user, :status => :created, :location => @user }
      format.html { render :action => "new" }
      format.xml  { render :xml => @user.errors, :status => :unprocessable_entity }
We want to change the error procedure for all our templates. Rails has a concept of helpers, which are loaded into all of the templates, so this is obviously the place to put our code. We also uses a same_user method to protect certain links and forms, this can also be placed in the view helpers file. So in app/helpers/application_helper.rb, we'll add the following lines:
# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
  ::ActionView::Base.field_error_proc = { |html_tag, instance|
    "<span class='fieldWithErrors'>#{html_tag}</span>"
Because we're inside a module, we have to reference ActionView by preceding it with the scope expression (::).

First Release

Now we're ready for our first release. Start up the server again:
ruby script/server
Open the browser and go to the location http://localhost:3000/users. You should now see something like this:
Clicking on Log in, without specifying the name and password, causes the error message to be displayed. Next we'll look at the show page (click on Show):
Now let's see what the edit page looks like. Log in as jhl with password villafranca, then click on Edit:
Next we'll check out the new user page, (click Log out, then New user):
Let's see what the error highlighting looks like now (click on Create):
Finally, creating a new user, also automatically logs in that user:
We seem to have resolved all the problems. That's as far as we're going in this lesson, so we'll give release 0.1 to the fictitious client, while we carry on coding – next week.

Source Files

All the source files for this lesson can be found in the archived file. Be warned, though – this is a 2 MB file. The password for both users (jhl and lug) is villafranca. The source code is licensed identically to Ruby on Rails, using the MIT license.

What's Next?

Next we'll complete our Ruby on Rails web application, by adding albums and pictures. Meanwhile, why not try out the current version of the application for yourself?


Wrapping the edit.html.erb template using the same_user? method is not by any means the best way to provide security in Rails. At the time I thought it would have taken too long to explain the intricacies of the filtering mechanism. I have since taken the WebAlbum application one step forward in an article I wrote on my company site, which provides such security. Feel free to take a look.