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:

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

test:
  ...

production:
  ...

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")
end

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
end

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")
  end
end

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">
    <p>
      <%= h(truncate(joke.joketext, 20)) %>
      <%= link_to 'Read this joke', {:action => 'show_joke', :id => joke} %>
    </p>
    <p class="author>
      by <%= h(joke.author.full_name) %></p>
  </div>
<% 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.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.jointfillah.com JointFillah

    Great blogpost!

    Ofcourse I couldnot ignore the whole RubyOnRails hype the last few months, so I had a few looks at it. But first looks dazzled me. This post clarifies a lot. Tnx for that ;)

    However, I am still not convinced about RoR being more than a hype. I am still having a hard time on the Syntax. And I think more people will have to same problem.

    Because I am more used to PHP/Java syntax, I was looking for a little less abstract solution. I found one in a project pretty similar to RoR (for as far as I can see), but still with the ‘easy’ php OO syntax: Symfony

  • Marc

    Coming from a Java background, I too found it difficult at first to adapt to the code. I am especially having trouble letting go of the XML configuration files so inherent in J2EE.

    However, I am still not convinced about RoR being more than a hype. I am still having a hard time on the Syntax. And I think more people will have to(sic) same problem.

    It *is* more than a hype, and whilst the syntax can be difficult to grasp especially for the more “traditional” coder, it shouldn’t mean the death of the thing.

    (Note I am not implying that this is the death of PHP or J2EE either. As many a wise programmer before me has stated; this is another tool for the toolbox)

  • Adam A Flynn

    I’m still very skeptical of something like this, but, all the SitePoint attention it has gotten lately has put it on my list of things to tinker with. Who knows, maybe when I get down to actually working with it I’ll change my mind.

  • http://www.hotgazpacho.com hotgazpacho

    I’ve been dabling in RoR for about a month now. Yes, it was had to let go of the configuration files and all the PHP code, and trust in RoR. It takes some getting used to for someone proficient in PHP, but I gotta say, I love it! One resource I have found particularly invaluable is the RoR Wiki. All kinds of cool stuff, like Authentication generator and Access Control Lists.

    RoR ROCKS!

  • Tvienti

    Nice intro. I’m one more developer that’s been vaguely aware of the hype of RoR, but I haven’t yet had the time to really see what’s going on. This seems to solve a lot of problems that I’ve solved or tried to solve on my own with a homegrown PHP framework. I’ll persist the echo: the syntax makes me feel funny things in my tummy.

    …but as long as you stick to the naming conventions … that Rails is based on, it all just works!

    This line was a significant turn off to me. I’m all about naming conventions, coding standards, I sometimes even get caught up deleting tabs in blank lines because I’m just a little OCD. But I don’t like the idea of something’s functionality being dependant on naming conventions, unless there’s some config directive or similar that can override the default behavior.

    Other than that, this seems like a very interesting technology. At the very least, it seems like it could crank out business-facing admin interfaces really quickly.

    T

  • virtualmice

    Same sort of remarks :

    After having developped my own PHP OO framework I discovered RoR.

    RoR just happens to be what RefleXiveCMS (my baby) should have become, only way better and with a language (Ruby) you don’t have to fight with for OO programming.

    There is no looking back.

  • Fenrir2

    unless there’s some config directive or similar that can override the default behavior.

    There is! An example of naming conventions:

    class User

    Because the classname is User this will look for a table users. But you can set your own table name:

    class User

    And you can even disable pluralization of classnames for tables or create your own pluralization rules (for another language for example).

    But you can save a lot of typing if you use the default behavior.

  • liberx

    Not having checked out RoR yet, this is a fantastic intro – and its similarities in concept with what I’ve done so far (despite underdevelopment) is uncanny – right down to the naming conventions!

    I’ll now have to check it out some more for sure, and perhaps some other frameworks “inspired by RoR” as well. Might just save a lot of time from reinventing the wheel yet again…

  • Dake

    Checking out Rails, and I am liking it… coming from a Perl background, I tend to say the opposite of what most people say on the syntax (most of the people commenting on syntax and grammar have a few spelling and grammar errors in there posts… I’ll leave who ever reads this to explore that line of thought more).

    With Java, you have nothing, really, to clue somebody in as to what a variable is. There are various notations to get around this, so this will mostly follow whatever convention your business uses.

    However PHP, with me coming from a Perl background, is about as ugly as they come, syntax wise. What, exactly is the point of the ‘$’ in PHP? ‘$’ in Perl means scalar or reference (which essentially are the same), ‘@’ means array, and ‘%’ means hash. Meanwhile in PHP, there is no difference between arrays and hashes (perhaps not that confusing, until you try to guess how a half hash, half array data type iterates). With Ruby, CAPITAL_LETTERS means its a constant being defined. $ means the variable is global (no messing with a function or super array to make something global). A variable in_lower_case (often using ada style notation) means it is an instance variable, and will disappear outside the current lexical scope. @@ means the variable is a member of the current object being modified. Saves you five letters out of typing $this->.

    The syntax is wonderfully designed. One just needs to understand it. Also, one needs to realize _everything_ in Ruby is an object. Even the number 5. hence code like the following make sense.

    
    # code untested... but a monkey should be able to figure out
    # how to fix any syntax errors.
    5.times do |x|
       print "Hello from the Ruby World"
    end