Lesson 4
Rails Models
In our previous episodes, we’ve described how the controller makes requests of the database, via the model. The controller collects, into variables, all the data the view needs to render the page, and then the view template creates the HTML page.
In this episode we explore models in more detail. We’ll step back and discuss some simple strategies to think through your data, how to define objects that represent that design, and how to tell Ruby on Rails about the objects. Then we’ll peel away the covers on using your models.
Object Definitions and ORM
In episode 2, we introduced the term Object-Relational Mapping or ORM. Ruby on Rails, through the ActiveRecord library, implements this technique for you. ORM allows you to think and work in terms of the objects of your application, rather than lower-level database tables and the language of those databases (structured query language or SQL). (Refer back to episode two or its show notes if you need a refresher on objects, classes, and associated terminology.)
To make best use of the ORM pattern, first consider your application and the information you want to model. You may want to list out your general requirements and it is often helpful to draw a sketch of how the chunks of data relate to one another.
Let’s do that now using our trusty example of this podcast and the web site that hosts it.
Our requirements listed out might be something like:
- A visitor to the site sees a list of podcasts with their title, description, and a link to an MP3 file
- If there is an associated show note for that podcast, a link appears that goes to a page displaying it.
- Each podcast is tagged with one or more topic categories which the visitor can see next to the podcast’s other information
Let’s briefly dissect this list of requirements to identify candidates for objects we want to model.
First, we have the podcast object itself. From our requirements, we have a title, description, and an MP3 filename, each of which is a string. We next see that each podcast has a show notes page associated with it. We could make show notes part of the podcast class directly, or we could put in in a separate object (which implies a separate table in the database). For this example, we’ll make it a separate object. There’s a one-to-one relationship between podcasts and show notes.
Continuing with our requirements, we see that podcasts can be categorized into different topic areas, or categories. To implement this, we need a set of category objects, each with an associated name string. One podcast can have many categories (e.g. this podcast is about Ruby on Rails generally and about Modeling specifically) and each category can have many podcasts associated with it. So there’s a many-to-many relationship between categories and podcasts.
Here’s a schematic drawing of the required objects:

How Rails implements Model Objects
Through the ActiveRecord object-relational mapping technology, Rails creates model classes that correspond to our database tables. The models come into life with a lot of capabilities, but you’ll typically want to customize and extend them to meet the specific requirements of your application.
We’re not going to cover the specifics of setting up your database. Rails supports all the major relational databases, including MySQL, PostgreSQL, Oracle, and DB2. MySQL is by far the most common. But for the most part, you don’t have to worry about the specific database; once you’ve completed a little setup, you interact only with your models, and ActiveRecord translates your requests to the appropriate database requests.
Migrations
Now it is time to turn our data model sketch into working code, which Ruby on Rails makes very easy.
You define your database tables, and thus their core attributes of your models, using something called a migration. A migration is a Ruby file that defines, in a simple, declarative way, what columns make up one row of a particular database table.
To continue with our example, we’ll need one migration that defines our podcast table, one that defines the show notes table, and one that defines the categories table.
The podcast migration, for example, reads something like this:
First, there’s some boilerplate code that tells Rails you are defining a table. Then you simply list each of the fields, and what type it is. For the podcast, this code reads:
t.string "title" t.string "description" t.string "filename"
(The fact that each of these starts with “t.” is a coding detail that we’re going to skip over for now.)
That’s all it takes to define the podcast table. Rails will automatically add a numeric ID field, so we don’t have to specify that.
Once you have created your migration files, you need to use them to actually set up the database itself. You do this using the Ruby utility called Rake. At your command line, you issue the command rake db:migrate. That runs all migrations currently defined that have not yet been applied to your database.
Working with our Podcast object
Once you’ve run this simple migration file, you now have a database table and a corresponding Podcast model. Working with the model is simple. To create a new podcast object, you use a very simple Podcast class and simply type:
episode = Podcast.new
And now you have an instance of the Podcast class, which you’ve named episode. Now, to set its attributes, you can simply write:
episode.title = "Learning Ruby on Rails" episode.filename = "learningrails-1.mp3" episode.description = "This episode covers..."
When this code is executed, you’ve created the episode object and filled it with data. Now it takes one more line of code, episode.save, to write the data to the database.
This is all so simple that it’s easy to miss how much magic is going on. Ruby on Rails Models are subclasses of the ActiveRecord library’s Base object. ActiveRecord provides a lot of basic functionality for free. ActiveRecord works by analyzing your database behind the scenes, and through the use of various naming conventions, builds up a set of methods for your object automatically. This is the ORM at work.
Now let’s find a podcast episode. Once again, our Podcast model class has been automatically imbued with some powerful capabilities. We can simply write:
episode = Podcast.find_by_title('Learning Ruby on Rails')
and we’ll get back a podcast object, called episode, with all the information about that podcast. We didn’t have to write the ‘find_by_title’ method; Rails automatically creates a find method for every attribute.
Now, if we wanted to access the description of that podcast episode, we just write episode.description.
Updating is as easy as finding an object, changing the desired attributes value and saving it again. Alternatively, Rails provides shortcut methods to find and update objects in one call (update). There are a couple of ways to delete information from the database as well.
There’s many other ways to write the code for these tasks, and we’ve glossed over some details, but I hope this gives you a good sense of how Rails creates objects that correspond to your database, and how you interact with those objects.
Adding the show notes
What about the show notes? Remember, we decided to put them in their own table. So we need another migration to define that table, the core of which is simply:
t.text "body" t.integer "podcast_id"
The body field is where we store the text of the show notes. (The column type of “text” instead of “string” tells the database to allow a potentially large amount of text.)
The podcast_id field is how Rails knows what podcast a particular show_notes object is associated with.
You could find the show notes for a particular podcast by doing something like this:
- Find the podcast you want, perhaps by searching for the title, and get its ID
- Find the record in the shownotes table that has the matching podcast_id
- Get the body from that shownotes record
That’s the hard way. Rails makes this easy by allowing you to define connections, called associations, among your models.
To set up the association, you add one line of code to each of the associated models’ classes. The podcast class gets a line that reads:
has_one :show_notes
and the show_notes model gets a line that reads:
belongs_to :podcast
With these two simple additions, you can now write episode.show_notes to access the show notes for a particular episode. The Rails code will automatically create a database query that uses both the podcast and the show_notes table, and that specifies that the podcast_id in the show_notes table must match the id of the selected episode.
Note that belongs_to and has_one are two sides of the same relationship. The side that has the id of the other table, called the foreign key, gets the belongs_to declaration. In our case, the show_notes table includes the podcast_id foreign key.
Adding categories
Now let’s add the ability to assign categories to a podcast. First, we need a migration to define our categories table. It is very simple — all it needs is a category name, which is a string. Rails automatically adds an ID column.
A podcast can have zero or more categories, and categories may have zero or more podcasts associated with them. This many-to-many relationship is defined with the tongue twisting declaration called “has and belongs to many”. In print, it is shortened to the acronym HABTM. In both the podcast and category classes, you write has_and_belongs_to_many :categories in the Podcast class and has_and_belongs_to_many :podcasts in the Category class.
But where is this information stored? The podcast model doesn’t have a field for a category_id — we wouldn’t know how many such fields to add, since a podcast can have any number of categories. And the same is true for the categories model; each category is associated with many podcasts, and maybe with entirely different things like articles, so we can’t put the podcast id in the categories table.
The solution is to use a technique called a join table to connect the two tables. Ruby on Rails will automatically make use of such a join table, but you have to define it outside of the individual classes’ migrations. ActiveRecord will automatically look for a table called categories_podcasts (it concatenates the plural form of the class names in alphabetical order).
So to make the HABTM relationship work, you need to create a migration for the join table, edit the table definition, and run the migration. The join table has two integer columns, one for the category_id and another for the podcast_id. (You also need to specify that this table shouldn’t get an ID field of its own, but we’ll skip the details of that for now.)
Now, with the join table created and the HABTM declarations in the two model files, we can simply write
episode.categories
and we’ll get back an array of category objects, one for each category that is associated with that particular episode. Rails automatically generates the SQL to tell the database to use the podcast table, the categories table, and the join table, and to match up the id fields properly.
The mechanics of generating migrations and models
In our discussion so far, we’ve mentioned a number of files that you work with to define your migrations and models in Ruby on Rails. While you can create these manually whenever you want, Ruby on Rails comes with a variety of utility scripts that are put in the scripts directory of your Rails application that makes this work much easier. One of these scripts is called “generate” and it can create models, migrations, controllers, and even view files for you. There are many other generator scripts available too, but we’ll come back to this topic in another podcast.
One other thing you should be aware of is that like other parts of Rails, migrations and models have their own set of conventions for naming things and placing files in your project. If you go with the flow and use conventions, all of features we talk about here today work automatically. If, for some reason, you need to do something else, Rails provides means for accomplishing this, but it is much more work on your part.
Validation
When a user enters data in a form, for example, you want your application to check that the data is valid before writing it to the database. This is called validation. Validation is handled in the model classes, so no matter whether the data is coming from a form, or a web services interface, or whatever, the business rules represented by the validations are enforced.
ActiveRecord provides a large number of helper methods that you can use to check things like whether a field is empty or falls out of a range of numbers, for instance. You can also write your own custom validation method that does whatever kind of checking you require. These methods can be set up to check the state of the object at different times. You might want to check that all fields are acceptable before saving the object into the database for the first time, or perhaps every time it is updated.
In our podcast model, perhaps we want to make sure that no two podcasts share the same title. We can make use of a validation helper and write validates_uniqueness_of :title at the top of our file. This call will execute every time our object is saved and will fail if a different object is already in the database with the same title. In the case of failure, ActiveRecord returns with a list of error messages. In the case of data entry in a form, the error messages would typically be displayed at the top of the form.
Relationship Methods
The relationship declarations, such as “belongs_to”, “has_one”, “has_many”, and “has_and_belongs_to_many”, do more than just signal to ActiveRecord how to interpret the model and store information in the database. Their associated code also triggers the inclusion of convenient methods for working with the model in a more intuitive manner.
For instance, belongs_to adds methods that allow you to directly work with the associated parent object. You can get and set the parent object directly, and even create a new parent. When using these methods, ActiveRecord takes care of saving the associated objects and updating their foreign keys for you. What makes this intuitive is that the method names are created through the name of the associated object’s class. So, in our podcast example, if you have a shownotes object and you want to refer to the associated podcast’s title, you would use Ruby code like myshownote.podcast.title. Specifying podcast this way automatically loads the associated podcast object for you.
On the other side of the relationship picture, the has_ methods also make life a bit easier, if slightly more complicated.
has_one provide the exact same set of functions as belongs_to, since you are creating a one to one relationship. If we had a podcast object in the variable episode, we could specify the shownote’s body text via episode.shownote.body. Unlike belongs_to, the has_ calls let you also specify some options to the relationship. Think of this as the owning or parent object being “in charge” of its child’s destiny. It decides what to do, for instance, when it is deleted. Does it also delete its child, just orphan it in the database, or otherwise leave it hanging?
has_many works in a one to many relationship, so it adds methods to add, delete, and update objects that work with one or more children.
has_and_belongs_to_many is like a bidirectional has_many relationship, and the methods added are similar. In our example, the podcast object could get all of its categories through episode.categories, and if you had a category object named mycategory, you could find all podcasts associated with it via mycategory.podcasts.
Summary
This concludes our brief peek into the inner workings of how Ruby on Rails implements models and object-relational mapping. To summarize, after you sketch out your model’s needs, you generate a series of model classes and associated migration files. You use the migrations to define the format of the data that is to be stored in your database, and you use your model classes and all of the power of ActiveRecord to manipulate that database from an object perspective.
ActiveRecord provides a number of tools to clearly specify how your classes relate to one another, and in return, it handles all of the messy database manipulation. In the process, it provides a selection of handy methods for easily and intuitively referring to your object’s relations, from any side of the relationship.
If future episodes, we’ll revisit models and look at many of the advanced things you can do with ActiveRecord, migrations, and other database tricks. We’ll also find time in the future to talk about the important topic of testing your models.
That’s it for this episode. In the next lesson we’ll look at how controllers, views, and models work together, using form processing as an example.
If you’ve enjoyed this podcast, please tell your friends. And if you’re willing to do us a big favor, visit the podcast’s digg.com page and give us a thumbs up.

Reader Comments
17 comments
good stuff
From: Rob Russell, 09/02/10 11:08 AM
great pace, great content
applause for good work
From: mr49online, 10/05/09 12:12 AM
Its really a nice tutorial for learning rails.... keep it up guys.... Thnx....
Error
From: Fletch, 01/29/09 05:16 AM
Something's gone wrong... neither the play nor download links work. Also the link to the schematic drawing image seems to be broken.
Net Beans 6.0
From: cherrian chin harada, 09/30/08 01:23 AM
Hi, I took a look at the " hands-on tutorial using Net Beans 6.0 for migrations... Do you recommend downloading it? Or just stick to Ruby on Rails? Net Beans seems a little bit over my head since I am total beginner on RoR... I what is your recommendation, do I need this information at this stage?
answer to Gurvinder about static pages
From: Vitaliy Khudenko, 09/02/08 04:25 AM
Gurvinder, I think these pages are not so static :) For example, information for AboutUs may change in time (and reality proves it does change). So IMHO the better way is to store changables in DB and give a user (or admin in a common case) to manage this info. If you really want to place static html-page you can put in your public dir. If Apache (or app router) finds correspondance of incoming URL to a page placed in public dir the controller will even not be invoked and your page will be sent to browser.
Show Notes is singular
From: Michael Slater, 07/16/08 02:38 AM
Gurvinder, sorry for my poor choice of names. The “shownotes” is the name for a single document (the “show notes” for one show). So confusingly, shownotes is actually a singular reference.
Postcast and Show notes Relationship
From: Gurvinder, 07/12/08 03:10 AM
I can see above that you have “has_one :show_notes” and “belongs_to :podcast” syntax to make the model aware of the relationship. My question is that why do we have shownotes in plural and podcast in singular. is is one of the Convention over Configuration thing or we can have podcast in plural too.
One more Issue
From: Gurvinder, 07/07/08 02:34 AM
I am trying to build my First test website with rails on my local machine. The problem is “What should i do about the static pages as Every website has AboutUs, home, etc” and most likely they are all static.
Please Advice.
Rails Models
From: Gurvinder, 07/05/08 02:16 PM
Thanx for your help in explaining the Model and ORM. I am a new bee for rails and ruby and was not sure where to start from. Can u guid me in the right direction where to go and look for info. about ruby on rails. I have lotsof info. but all is Scattered.
Please advice.
More on join tables and references
From: Michael Slater, 05/04/08 03:04 AM
Steve, yes, join tables are used only for HABTM relationships. If a model has a has_one or has_many relationship, then the opposite side of the relationship has a belongs_to declaration, and the table for that model stores the foreign key (the id of the record in the other table). Good point on the t.references :podcast option. This is a new Rails 2.0 feature and I’m used to the old way, but this is a potentially cleaner way to specify a foreign key.
Table name
From: Michael Slater, 05/04/08 03:02 AM
Erwin, you’re correct, that’s a typo. In fact, if the model is called shownote and the table shownotes, which would be the convention, then the code should be has_one :shownote.
Join tables and IDs
From: Michael Slater, 05/04/08 03:02 AM
Ray, join tables in a HABTM relationship cannot have ids. There is no model associated with the join table, so you can’t reference it directly. You can use has_many :through to use a model table as a join table.
join table clarification
From: Steve, 05/03/08 03:59 AM
So do I gather from the comments below that the “rule of thumb” for when a join table is required is the “habtm” relationship? You don’t need a join table to associate a singular podcast with its singular shownotes, but you do need a join table to associate multiple podcasts with multiple categories?
Unrelated side note: I found that my brain accepts the “references” keyword in a migration pretty well. So when you write the migration for shownotes, instead of t.integer “podcast_id” one could write t.references :podcast I believe the end result is the same (a database field named “podcast_id”), but it helps clarify that this is a foreign key used in establishing a relationship. Might be helpful to someone.
table name
From: Erwin Odendaal, 05/02/08 10:51 PM
I presume that “has_one :show_notes” actualy has to be: “has_one :shownotes” since the table’s name is “shownote s” and not “show_notes”?
Join Tables
From: Ray, 05/02/08 01:30 PM
You make a point that the join table doesn’t get an id of its own, but wouldn’t it be useful to be able to refer to a specific podcast-category relationship? Why did you choose to leave out the id?
Join tables
From: Michael Slater, 04/26/08 04:09 AM
Pravin, the join table is not automatically generated. You need to create the join table (typically by creating a migration file). The join table has only two columns, one each for the ids of the two tables being joined. It does not have an id column of its own. There is no model that corresponds to the join table.
ROR -query related to join table
From: pravin shiraskar, 04/25/08 09:00 PM
i don’t understand join table ,it is automatically created when we mention "has_and_belongs_to_many”or we have explicitaly created model for that and why shouldn't get an ID field of its own,