3.1.
belongs_to
The most common database relationship is
many-to-one.
"#rubyrails-chp-3-fig-1">Figure 3-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: a
slideshow consists of many slides, but each slide (a photo combined
with a position) can belong to only one slideshow. To give us the
flexibility that we need (we'll also want the ability to reuse
photos in different slideshows), we'll need another relationship
between photos and slides, but let's leave that for later.
As before, let's create our database tables in a
migration, so it will be easy to back out any unnecessary changes.
Generate a model and migration to create a new class for
Slide, and another for Slideshow:
ruby script/generate model Slideshow
ruby script/generate model Slide
Rails generates the models and migrations for
slideshows and slides. Now, edit the new migration in db/migrate/create_slideshow.rb. As before,
we'll create steps to migrate up and down. The up step
will create the slides and slideshows tables, and the down
step will drop them, like this:
class CreateSlideshows < ActiveRecord::Migration
def self.up
create_table "slideshows" do |t|
t.column "name", :string
t.column "created_at", :datetime
end
end
def self.down
drop_table "slideshows"
end
end
Edit the new migration in db/migrate/create_slide.rb, like this:
class CreateSlides < ActiveRecord::Migration
def self.up
create_table "slides" do |t|
t.column "position", :integer
t.column "photo_id", :integer
t.column "slideshow_id", :integer
end
end
def self.down
drop_table "slides"
end
end
You can now run the migrations:
rake migrate
If you want, you can verify that you have slide
and slideshow tables in your database. If you decide that adding
these tables was a huge mistake, you could back up to the previous
version by typing rake migrate VERSION=1, which would run
the down method in all migrations greater than 1, starting
with the greatest. You can move to any version number in this way.
Be careful, though: if your migration drops a table, you'll lose
that data.
At this point, some data to test the new
relationships would be nice. Because we're not running these in
formal tests or in production, let's create some simple SQL
scripts. Create a script called
slideshow_data.sql:
insert into slideshows values (1, 'Interesting pictures', now( ));
insert into slides values (1, 1, 1, 1);
insert into slides values (2, 2, 2, 1);
insert into slides values (3, 3, 3, 1);
insert into slides values (4, 4, 4, 1);
insert into slides values (5, 5, 5, 1);
insert into slides values (6, 6, 6, 1);
insert into slides values (7, 7, 7, 1);
insert into slides values (8, 8, 8, 1);
insert into slides values (9, 9, 9, 1);
insert into photos values (1, "balboa_park.jpg");
insert into photos values (2, "camel.jpg");
insert into photos values (3, "cat_and_candles.jpg");
insert into photos values (4, "hut.jpg");
insert into photos values (5, "mosaic.jpg");
insert into photos values (6, "polar_bear.jpg");
insert into photos values (7, "police.jpg");
insert into photos values (8, "sleeping_dog.jpg");
insert into photos values (9, "stairs.jpg");
First, migrate down to zero and back up by
typing rake migrate VERSION=0 and then rake
migrate to make sure that you're starting from scratch. These
commands will drop all of the tables and create them again. Start
the MySQL prompt, type use photos_development, and execute
the script by typing source db/slideshow_data.sql at the
MySQL prompt. Now that you have working tables, you can edit the
new model in app/models/slide.rb.
Add the relationship between slides and slideshows to the new
Slide model class:
class Slide < ActiveRecord::Base
belongs_to :slideshow
belongs_to :photo
end
Save your changes, and you've got a working
belongs_to relationship from Slide to
Slideshow and another from Slide to
Photo. To see it in action, go back to the Rails console.
(If you closed the console, type ruby script/console to
restart it.) Type the lines in bold:
>> slide = Slide.find 1
=> ...
>> slide.photo.filename
=> "balboa_park.jpg"
>> slide.slideshow.name
=> "Interesting pictures"
belongs_to introduces the
photo and slideshow instance variables on
slide, and also some behavior.
"#rubyrails-chp-3-table-1">Table 3-1 shows the methods added to
the model by the belongs_to method.
Table 3-1. Metaprogramming for belongs_to
and has_one
|
Added Feature
|
Description
|
|
Methods
|
|
<association>.nil?
|
Test the association for a nil value:
slide.photo.nil?
|
|
build_<association>
|
Build an object of the associated type. Do not
initialize the built object to the root object:
slide.build_photo(:filename => "cat.jpg"
In this example, photo.slide is
initialized to nil.
|
|
create_<association>
|
Create 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:
slide.create_photo({:filename => "cat.jpg", :name =>
"cat"}
|
|
Attributes
|
|
<association>
|
An attribute of the type of the associated
object: belongs_to :photo on Slide allows
slide.photo and slide.photo = nil
|
belongs_to is only the "many" end of a
many-to-one relationship. Let's look at the "one" side.
 |