Ruby on Rails is taking Web development by storm. Let's start with a refresher on the underlying technologies:
- Ruby is the free, simple, straightforward, extensible, portable, interpreted scripting language for quick-and-easy object-oriented programming that, like Perl, sports many features to process text files and perform system-management tasks.
- Rails is a full-stack, open source Web framework in Ruby for writing real-world applications with more ease and less code.
Being a full-stack framework means that all layers in Rails are built to work together so you don't repeat yourself and can use a single language from top to bottom. Within Rails, everything (templates to control flow to business logic) is written in Ruby. Rails favors reflection and runtime extensions over configuration files and annotations.
This article details the components of Rails and shows you how it works.
The first thing to understand about Rails is its model/view/controller (MVC) architecture. While this approach is not unique to Rails -- or even to Web applications as opposed to other programs -- Rails provides a very clear and focused MVC way of thinking. If you stray from the MVC approach, Rails becomes far less useful than if you follow its paradigm.
The model part of a Rails application is primarily the underlying database it uses. In fact, in many ways a Rails application is just a way to perform manipulations on the data in a relational database management system (RDBMS) in a directed way.
A central component of Rails is the class ActiveRecord, which maps relational tables to Ruby objects and thereby to the data manipulated by controllers and shown in views. Rails applications are particularly likely to use the ubiquitous MySQL database, but bindings exist for a number of other RDBMSs, including IBM® DB2®.
If you like, you can add Ruby code to perform extra validation within an application model, enforce data relationships, or trigger other actions. The Ruby files within an application's app/models/ directory can call a variety of validation methods of ActiveRecord. However, you can also leave the model code as a stub as well and rely only on the constraints of the RDBMS that holds the data. For example, the application I develop in this example contains only this skeleton model code (at least initially):
Listing 1. Skeleton model app/models/contact.rb
class Contact < ActiveRecord::Base end |
Controllers carry out your application logic in its abstract form. That is, the Ruby scripts in an application's app/controllers/ directory will load model data into variables, save it back, and massage and manipulate it. But controllers are not concerned with how the data is concretely presented and entered by users. In the general MVC paradigm, this can allow the user multiple styles of interaction with the same controller: a native GUI, a Web interface, and a speech interface for the visually impaired might all interact with the same controller.
Rails is not quite so general as that, though; instead, it is more narrowly focused on providing and collecting data within Web pages. Nonetheless, you can modify the layout of those Web pages -- colors, fonts, tables, stylesheets, etc. -- independently of controller code.
Rails views are where we leave Ruby code. Rails contains a very nice template language for .rhtml files that combines pure HTML with embedded Ruby code. The very surface appearance of a Rails application screen is generally controlled by CSS stylesheets. The .rhtml format is an enhancement of HTML. Actually, a simple HTML file by itself is also a valid RHTML template, but there is not much point in omitting the scripting control that RHTML gives you.
RHTML is a true template format -- not simply a way of embedding code in HTML -- and this is a much more powerful approach. If you're familiar with PHP, think of the contrast between PHP itself and Smarty templates. That is, embedded scripting just intermixes code with uninterpreted HTML; the code portion is still responsible for issuing print statements when it wants to say something to the client.
In contrast, a template engine adds a custom set of tags to HTML that allows you to express conditions, loops, and other logic as part of the enhanced HTML markup.
The tools that Rails provides are basically a set of code generators. I like this approach much better than that of a development environment that forces me to use a rigid workspace and IDE. Rails does not get in your way, but nonetheless saves most of the work of manual programming -- or at least eases you into the parts that require manual coding by providing first-pass scaffolding "for free."
The concept of scaffolding is a central notion in Rails. Very simple applications can almost entirely avoid custom coding by letting Rails dynamically generate client HTML pages as it runs. A first pass at code generation creates just the raw scaffolding; you can subsequently generate more specific controllers, views, and models that you can customize. But you need not generate much to get started.
Rails relies on a fixed and fairly common-sense organization of its files, but this organization is relatively rigid. You will just be picking a fight with the Rails environment if you try to force other file and code organizations. Then again, I cannot see a reason not to go along with the organization Rails provides; for the most part, it "fits your brain" (as Ruby fans like to say). For example, the directory names and their organization are probably pretty darn close to what you would choose if you were designing a framework from scratch (at least if you think in the "Ruby way").
Several tutorials are available on the Ruby on Rails Web site that can walk you through creating a simple Rails application (see Resources). The sample application here is like them, since there is a certain way to get started right in building a Rails application. Given the relatively short length of this introduction, I do recommend one of those longer tutorials so you can get a more thorough grounding.
The sample application is a basic address book. It demonstrates the general steps for creating an application:
- Generate the model (in which you create a MySQL database and table).
- Generate the application (includes generating basic code and directories).
- Get Rails running (and configure database access).
- Create some content (includes generating the scaffold model and controller and telling the controller to use the scaffold).
We'll look at each step in detail.
Generating the AddressBook model
The first thing you need to do for any application is create a database for its data to live in. Technically, this step need not occur first, but it needs to occur early; it should be obvious that you should create the database before any application code, even automatically generated code. So let's create a database in MySQL and craft a first table within this database. (Consult other documentation for how to get MySQL or another RDBMS up and running.)
Let's assume MySQL is installed and available.
Listing 2. Creating a MySQL database and table
[~/Sites]$ cat AddressBook.sql CREATE DATABASE IF NOT EXISTS AddressBook; USE AddressBook; CREATE TABLE IF NOT EXISTS contacts ( id smallint(5) unsigned NOT NULL auto_increment, name varchar(30) NOT NULL default '', created_on timestamp(14) NOT NULL, updated_on timestamp(14) NOT NULL, PRIMARY KEY (id), UNIQUE KEY name_key (name) ) TYPE=MyISAM COMMENT='List of Contacts'; [~/Sites]$ cat AddressBook.sql | mysql |
There are a couple things to notice in this first table. Of central importance is that every table must have an id column with exactly that name. Rails uses the primary key column id for various recordkeeping and referencing tasks. The fields created_on and updated_on are not required, but if you do include them, Rails maintains them automatically "behind the scenes"; in most cases there is no harm in using these timestamps. So the only "real" data you have yet added is a name for your address book contacts.
Another little oddity exists with the Rails' use of singular and plural names for various things. Various items are renamed between singular and plural versions depending on their usage and context. Table names should use the plural form. I have not experimented with words having irregular plurals; words like datum and data might trip up Rails.
Generating the AddressBook application
Now that you have a database to interact with, create the AddressBook application. The first step is simply running rails to generate the basic directories and scaffold code:
Listing 3. Generating basic code and directories
[~/Sites]$ rails AddressBook create create app/apis create app/controllers create app/helpers create app/models create app/views/layouts create config/environments create components [...] create public/images create public/javascripts create public/stylesheets create script [...] create README create script/generate create script/server [...] |
I have abridged the output from running rails; the omitted lines just remind you of various files and directories that were created. Try it on your system and browse through all the created files. I've displayed a few of the most important files and directories in the code.
Having created the AddressBook/ directory and needed children, you need to perform just a bare initial configuration. First, set the database by modifying a YAML configuration file like so:
Listing 4. Configure database access
[~/Sites]$ cd AddressBook [~/Sites/AddressBook]$ head -6 config/database.yml # after editing development: adapter: mysql database: AddressBook host: localhost username: some_user password: password_if_needed |
Finally, you need to serve the data. Rails comes with its own single-function Web server, WEBrick, which is perfectly good for our experiment. You might also follow instructions at the Ruby on Rails Web site to configure Apache or other servers to serve Rails applications via FCGI (or plain CGI, but plain CGI will be slow).
Listing 5. Kicking over the WEBrick server
[~/Sites/AddressBook]$ ruby script/server -d => Rails application started on http://0.0.0.0:3000 [2005-03-21 17:57:38] INFO WEBrick 1.3.1 [2005-03-21 17:57:38] INFO ruby 1.8.2 (2004-12-25) [powerpc-darwin7.8.0] |
The prior steps are enough to let you view a welcome splash page on the WEBrick port. For example, on my local system, I can now view http://gnosis-powerbook.local:3000/. But you need to generate just a bit more code to manipulate your custom database. You can do this with the script generate, which was created within your AddressBook/ application directory:
Listing 6. Code generation of scaffold model and controller
[~/Sites/AddressBook]$ ruby script/generate model contact
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/contact.rb
create test/unit/contact_test.rb
create test/fixtures/contacts.yml
[~/Sites/AddressBook]$ ruby script/generate controller contact
exists app/controllers/
exists app/helpers/
create app/views/contact
exists test/functional/
create app/controllers/contact_controller.rb
create test/functional/contact_controller_test.rb
create app/helpers/contact_helper.rb
|
Notice here that you should use the singular contact rather than the plural contacts in the corresponding table name.
Now you need to edit one more generated file, just a bit, to get the controller to use the scaffold:
Listing 7. Telling the controller to use the scaffold
[~/Sites/AddressBook]$ cat app/controllers/contact_controller.rb class ContactController < ApplicationController model :contact scaffold :contact end |
Now you can view and modify the contents of your database at a URL like http://rails.server/contact/ (in my test case, it's http://gnosis-powerbook.local:3000/contact/). After entering a little data, it looks something like Figure 1 and Figure 2:
Figure 1. Listing contacts

Figure 2. Editing contact

The previous code creates a fully working interface to view and modify your database, but all the formatting, presentation, and business logic (such as there is) are done dynamically by Rails without any great sophistication. In order to create something a bit more custom, you need to generate a bit more code. What we need now is for Rails to explicitly write out all the scaffolding it is implicitly generating on the fly so that we can tinker with it.
Listing 8. Code generation of explicit controller and view
[~/Sites/AddressBook]$ ruby script/generate scaffold Contact
dependency model
[...]
create app/views/contacts
exists test/functional/
create app/controllers/contacts_controller.rb
create test/functional/contacts_controller_test.rb
create app/helpers/contacts_helper.rb
create app/views/layouts/contacts.rhtml
create public/stylesheets/scaffold.css
create app/views/contacts/list.rhtml
create app/views/contacts/show.rhtml
create app/views/contacts/new.rhtml
create app/views/contacts/edit.rhtml
|
Now there's a bit more to work with, so try modifying a few things. (Notice that this code has gone back to the plural form contacts, for reasons not clear to me; we need to accept it for now.) Try changing a few colors and fonts in the CSS:
Listing 9. Configuring the cascading stylesheets
[~/Sites/AddressBook]$ head -8 public/stylesheets/scaffold.css
body { background-color: #ffe; color: #338; }
body, p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
}
td { border: 1px solid; }
a { color: #eef; background-color: #446; }
a:hover { color: #fff; background-color:#000; }
|
Now that you have the code, what does contacts_controller.rb do? It is more explicit and configurable in its action than the contact_controller.rb you saw in the previous code. In part, the controller looks like this:
Listing 10. Controller app/controllers/contacts_controller.rb
class ContactsController < ApplicationController
def list
@contacts = Contact.find_all
end
def show
@contact = Contact.find(@params['id'])
end
def create
@contact = Contact.new(@params['contact'])
if @contact.save
flash['notice'] = 'Contact was successfully created.'
redirect_to :action => 'list'
else
render_action 'new'
end
end
|
As promised, a controller's main job is to load data into variables. The object Contact is the ActiveRecord object-relational mapping that the model provides. The variables @contacts or @contact are given data in their appropriate methods. The methods are themselves referred to by URLs such as http://rails.server/contacts/show/2 (this one shows the contact with id of "2").
The controller in this example ultimately connects to views, RHTML files that make use of the data values loaded into variables by the controller. For example, here's part of the list view:
Listing 11. List view app/views/contacts/list.rhtml
[...]
<% for contact in @contacts %>
<tr>
<% for column in Contact.content_columns %>
<td><%=h contact.send(column.name) %></td>
<% end %>
<td><%= link_to 'Show', :action => 'show', :id => contact.id %></td>
<td><%= link_to 'Edit', :action => 'edit', :id => contact.id %></td>
<td><%= link_to 'Destroy', :action => 'destroy', :id => contact.id %></td>
</tr>
<% end %>
[...]
|
The method ContactsController.list loads the variable @contacts, and the flow control tags in RHTML pull out the individual records from the array.
The initial model contained only a name for a contact. Unfortunately, I don't have room in this article to expand the model to include actual contact data like phone numbers, addresses, emails, etc. In general, that data would live in a child table with a foreign key relation to the table contacts. The Rails model would indicate the relation with custom code something like this:
Listing 12. Custom code app\models\phone.rb
class Phone < ActiveRecord::Base belongs_to :contact end |
Before wrapping up, let's change the data model just slightly and see how that affects the application. First, add a column:
Listing 13. Adding first_met date to model
$ cat add-contact-date.sql USE AddressBook; ALTER TABLE contacts ADD first_met date; $ cat add-contact-date.sql | mysql |
Now that you've changed the underlying model, http://rails.server/contact/ -- the behind-the-scenes version of the scaffolding -- simply adjusts with no effort on your part. The controller and view are fully automated based on the model. But the application version at http://rails.server/contacts/ with our hand-tweaked files is not quite as automatic.
The list view automatically looks for all the columns, whatever they might be, by including Contact.content_columns as part of the template loop. But other views such as edit have already been generated, and you need to add your new data fields. For example:
Listing 14. Edit view app/views/contacts/edit.rhtml
<h1>Editing contact</h1> <%= error_messages_for 'contact' %> <%= start_form_tag :action => 'update' %> <%= hidden_field 'contact', 'id' %> <p><label for="contact_name">Name</label><br/> <%= text_field 'contact', 'name' %></p> <p><label for="first_met">Known Since</label><br/> <%= date_select "contact", "first_met", :use_month_numbers => false %></p> <input type="submit" value="Update" /> <%= end_form_tag %> <%= link_to 'Show', :action => 'show', :id => @contact.id %> | <%= link_to 'Back', :action => 'list' %> |
So what does your hand-tweaked application look like? Not a lot different from the default, but you can see your modifications in action in Figures 3 and 4:
Figure 3. Listing contacts modified

Figure 4. Editing contact modified

Rails gives you an extremely quick way to develop flexible Web applications; this introduction just barely touched on what it's like to work with Rails. The full framework contains many useful classes and methods for carrying out the actions most used in Web-based applications.
The best thing about Rails is that it fosters a whole "Rails way of thinking," since it comes complete with all the supporting code you need. This is a big plus over other toolkits and frameworks that just give raw materials to work with. Rails development offers you a clear path from a half-formed idea to a fully functioning Web application.
-
"Deploy an application with Cerise Web server" (developerWorks, February 2005) shows how to create a guestbook Web application with the Cerise Web server and Ruby.
-
The home page for Ruby on Rails is the place to get started with introductory tutorials, guides, and downloadable source and documentation.
-
For a list of databases that Ruby on Rails supports, including IBM DB2, check the Database Drivers page.
-
This ten-minute video shows real-time development of someone working on a Ruby-based Web application.
-
Wikipedia has an excellent entry on the MVC architectural paradigm.
- Find more resources for Linux developers in the developerWorks Linux zone.
- Get involved in the developerWorks community by participating in developerWorks blogs.
- Browse for books on these and other technical topics.
- Innovate your next Linux development project with IBM trial software, available for download directly from developerWorks.

To David Mertz, all the world is a stage; his career is devoted to providing marginal staging instructions. For more on his life, see his personal Web page. He's been writing the developerWorks columns Charming Python and XML Matters since 2000. Check out his book, Text Processing in Python. You can contact David at mertz@gnosis.cx.



