Programming - - By Kevin Yank

Ruby on Rails: a look at the code

Ruby on Rails got its reputation based on how little code you have to write to get common Web development tasks done. But what about the code that you do have to write? Since yesterday’s post announcing Ruby on Rails 1.0, a lot of people have chimed in asking what it’s like when you get past the hype.

The following is republished from the Tech Times #128.

Ruby on Rails is the poster child for a principle of agile development frameworks: convention over configuration. What this means in practice is that, instead of having to write a bunch of configuration files and standard boilerplate code for every project you undertake, you can simply code to a set of assumptions and all that grunt work will be done for you.

As a result, the experience of examining Ruby on Rails code for the first time can be bewildering. “Where does the @posts variable come from, and how does it get filled with database records?” you might wonder. Because you have a database table called posts, and Rails hooks it all up for you.

With very few exceptions, the only time you need to write code in Rails is when your needs are different from the most common case.

With this in mind, the first code you write is a little file called database.yml that tells Rails how to connect to your database, so that it can set up all those intelligent defaults. You can set up separate databases for development, testing, and production:

  adapter:  mysql
  database: jokes_development
  host:     localhost
  username: username
  password: password



With this file in place, you can run a command to generate a Rails scaffold, which is a set of auto-generated files that let you display, create, update, and delete database records using a set of Web pages. Application development then becomes a process of slowly modifying and replacing that auto-generated code to get the specialized functionality you want.

Rails follows a Model-View-Controller (MVC) pattern in the code it generates. A Rails application is therefore made up of objects based on database records (the model), Web pages to display and edit those objects (the view), and a set of actions that tie the two together (the controller).

Editing the model files lets you control how records are pulled out of the database. Say you want to be able to show only jokes that have been marked for publication. You’d modify the joke.rb file that defines the model for jokes in the database:

def self.published_jokes
  find(:all, :conditions => "published = 1")

We can then modify the default action (which is called index) in our joke list controller (jokelist_controller.rb) to display a list of published jokes, instead of all jokes (the default):

def index
  @jokes = Joke.published_jokes

We can also modify our model (joke.rb) to set up some requirements (e.g. a joke must contain text, and that text must be unique) on newly-created or updated jokes that are submitted through the admin interface:

class Joke < ActiveRecord::Base
  validates_presence_of :joketext
  validates_uniqueness_of :joketext
  def self.published_jokes
    find(:all, :conditions => "published = 1")

Very “talking out loud” sounding names like validates_presence_of and validates_uniqueness_of are common in Ruby. It’s easy to be thrown by these after the terseness of most other languages, but when you realise that in Ruby you trade having to remember complicated XML configuration file syntax (common in Java) for these very readable names, you’ll adjust quickly.

Once you’ve got the logic of the model right, you’ll want to adjust the Web pages that present the model to the user (the view). In Rails, you typically build pages using a simple template language called Embedded Ruby (ERb). ERb lets you create .rhtml files that contain inline Ruby code, but because most of your application’s logic will be in the model and controller, the code that goes in your .rhtml files is generally limited to short snippets that output dynamic values or loop through sets of records to output a piece of HTML once for each record.

If in our joke listing template (index.rhtml) we wanted to display only the first 20 characters of each joke, we might modify the template code to look like this:

<% for joke in @jokes %>
  <div class="joke">
      <%= h(truncate(joke.joketext, 20)) %>
      <%= link_to 'Read this joke', {:action => 'show_joke', :id => joke} %>
    <p class="author>
      by <%= h( %></p>
<% end %>

First up, this code loops through all of the jokes in the collection we set up in our controller above. For each joke, it outputs the first 20 characters (using the built-in truncate method), escaping any HTML special characters (using the built-in h method). It then outputs a hyperlink with the text “Read this joke” that will link to another Rails action called show_joke, passing it the ID of the current joke in the query string. The built-in link_to method makes creating links like these easy.

Lastly, we output the name of the joke’s author. For this to work, we’d need to set up another Rails model for authors stored in our database. Letting Rails know about the relationship between these two models is straightforward:

class Joke < ActiveRecord::Base
  belongs_to :author

class Author < ActiveRecord::Base
  has_many :jokes

Coming from other languages, it’s difficult to trust that that’s all the code you need to set up a relationship between two classes based on database tables, but as long as you stick to the naming conventions (the jokes table in your database must have an author_id field that contains values from the id field in the authors table) that Rails is based on, it all just works!

This has been a very brief overview of what it’s like coding in Ruby on Rails. There are some great tutorials out there (check the comments to my previous blog post) that will hold your hand through creating a complete application, but in short, once you’ve grasped the way Rails implements the model-view-controller application structure, learning Rails is simply a matter of learning the naming conventions and all the built-in methods that are there to help you.