You’ve seen how Active Record treats a model backed by a single table. You wrote very little code, and got impressive behavior for free. But Photo Share will need many different models working together. In this chapter, you’ll learn how to deal with relationships. Active Record takes advantage of the Ruby language and naming conventions to simplify the way you work with related tables through related models.
In Chapter 3, you got a taste of Active
Record’s language for relationships and validations. Adding the macro
validates_presence_of :filename
record to
the class added all of the code that your class needed to support
validation. You’ll deal with relationships the same way. Rather than adding
a bunch of methods and attributes to your class explicitly to manage a
foreign key relationship, you’ll describe the relationship using a little
bit of syntax called a macro and let Active Record do the rest. Rails will
add everything you need to manage each relationship based on a few short
lines of code.
You’ll specify a relationship, also called an association, in three parts: the relationship macro, the association or target, and an optional hash of additional parameters. For example, this code:
class Slideshow < ActiveRecord::Base has_many :slides, :order => 'position'
specifies that a single Slideshow
has_many
:slides
, and
they are ordered by the position attribute. The macro is has_many
, the association is :slides
, and the hash of options is {:order => 'position'}
.
Let’s add relationships to the existing Photo
, Slide
,
Slideshow
, and Category
classes. If you haven’t already done so,
and you want to start coding your way through the book with us, copy your
code from http://www.oreilly.com/catalog/9780596522001, using the file
for Chapter 3. Run rake
photos:reset
to run your migrations and reset your test data. Now
you’re ready to follow along.
The most common database relationship is
many-to-one. Figure 4-1 shows how Active
Record maps the “many” side of such a relationship. In Photo Share, we
want users to be able to build slideshows. A slideshow contains an ordered list of pictures. We can’t
simply use pictures in a slideshow because a picture has no way of keeping
its position in a slideshow, so we’ll introduce a Slide
class. We’ll then need a many-to-one
relationship between slides and slideshows because a slideshow consists of
many slides, but each slide (a photo combined with a position) can belong
to only one slideshow. A slide also belongs to a photo. We’ll implement
both relationships with belongs_to
.
You’ve already generated a model and migration for Slide
, and another for Slideshow
. You can open up
db/schema.rb to verify that your Photos schema has a
table called slides and another called photos. Notice that the slide has a
slideshow_id
and a photo_id
. Any model that uses belongs_to
must be backed by a table that has
the supporting foreign key. Next, modify the Slide
model in
app/models/slide.rb, adding the two
relationships:
class Slide < ActiveRecord::Base belongs_to :slideshow belongs_to :photo end
That’s it. You have two working belongs_to
relationships. Verify them briefly in
the console. (Remember, you can start the console with ruby script/console
, or simply use reload!
to reload it whenever your models
change.)
>> slide = Slide.new => #<Slide id: nil, position: nil, photo_id: nil, slideshow_id: nil, created_at: nil, updated_at: nil> >> slide.create_slideshow => #<Slideshow id: 2, name: nil, created_at: "2008-05-10 17:45:46", updated_at: "2008-05-10 17:45:46"> >> slide.photo = Photo.find(2) => #<Photo id: 2, filename: "lighthouse.jpg", thumbnail: "lighthouse_t.jpg", description: "My ride to work", created_at: "2008-05-21 02:07:29", updated_at: "2008-05-21 02:07:29"> >> slide.photo.filename => "lighthouse.jpg" >> slide.slideshow.id => 2
You can see the belongs_to
relationship at work.
You have at least two new attributes: slideshow
and photo
. You also have the create_slideshow
and create_photo
methods. These methods are only the
tip of the iceberg. Table 4-1 shows all
of the methods and attributes introduced by the belongs_to
macro.
Table 4-1. Metaprogramming for belongs_to and has_one
Added Feature | Description |
---|---|
Methods | |
Test the association for a nil value:
| |
Build an object of the associated type,
but do not save it yet: In this example, | |
Create and save an object of the
associated type, initialized to the root object. It takes a hash
map of attributes for the new object as a parameter: | |
Attributes | |
An attribute of the type of the
associated object: |
As you can see, just learning the macros isn’t enough. To learn
about using Active Record to the fullest, you need to understand all of
the methods and attributes that belongs_to
creates for you. You’ll find the
association attribute and the constructors—all forms of build and create
methods—particularly useful. We’ll show you tables such as Table 4-1 for each macro we cover.
In the meantime, let’s take another look at the new models in the Rails console:
>> slide = Slide.find 1 => #<Slide id: 1, position: 1, photo_id: 1, slideshow_id: 1, created_at: "2008-05-10 17:45:34", updated_at: "2008-05-10 17:45:34"> >> slide.photo.filename => "train.jpg" >> slide.slideshow.name => "Interesting Pictures"
belongs_to
is only the “many” end
of a many-to-one relationship. Let’s look at the “one” side.
Get Rails: Up and Running, 2nd Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.