has_many

Now that you’ve finished the relationships on Slide, you’ll need to implement has_many relationships on Photo and Slideshow. Figure 4-2 shows the mapping between Active Record objects and database tables with has_many.

The entity (slideshow) has_many :associations (slides) relationship is a one-to-many relationship

Figure 4-2. The entity (slideshow) has_many :associations (slides) relationship is a one-to-many relationship

has_many is the other side of a belongs_to relationship. Both models and the schema exist, so you don’t need to modify the class or table for Slide. You can merely add the relationship has_many to slideshow.rb in app/models/slideshow.rb:

class Slideshow < ActiveRecord::Base
  has_many :slides
end

You’ll do the same to app/models/photo.rb:

class Photo < ActiveRecord::Base
...             
  has_many :slides
  validates_presence_of :filename
...
end

We should explain a little bit about the model. A slide belongs to a photo, but a photo has many slides. With this design, you give users the ability to use the same photo in several different slideshows. Remember: a slide is a photo and a position in a specific slideshow. So, a slide can’t be reused, but a photo can.

With those code changes, you can see all of the slides associated with a photo and all of the slides in a slideshow. As usual, you can open the console to see the model in action:

>> reload!
Reloading...
=> true
>> 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">
>> slideshow = slide.slideshow
=> #<Slideshow id: 1, name: "Interesting Pictures", created_at: "2008-05-10 17:45:34", 
updated_at: "2008-05-10 17:45:34">
>> slideshow.slides.each {|s| puts s.photo.filename}
train.jpg
lighthouse.jpg
gargoyle.jpg
cat.jpg
cappucino.jpg
building.jpg
bridge.jpg
bear.jpg
baskets.jpg
=> [#<Slide id: 1, ...]

So, you get a list of slides in the slideshow, and each has an associated photo. Active Record is now managing the has_many relationship between Slideshow and Slide. You could use photo.slides in the same way. Table 4-2 shows you the metaprogramming for has_many.

Table 4-2. Metaprogramming for has_many

Added feature

Description

Methods

<associations> << object

Adds an object to the <associations> collection: photo.slides << a_slide

<associations>.delete object

Deletes an object in the <associations> collection. The objects will be destroyed if the dependent parameter of has_many is set to true: photo.slides.delete a_slide

<associations>_singular_ids collection

Replaces the <associations> collection with a collection of objects identified by ids in the collection: photo.slides_singular_ids [1, 2, 3, 4]

<associations>.find

Uses the same rules as a basic find, but operates only on the items in the <associations> collection: photo.slides.find_by_position 4

<associations>.clear

Deletes all of the objects in the association: photo.slides.clear

<associations>.empty?

Tests to see if <associations> collection is empty: photo.slides.clear

<associations>.size

Returns the number of items in the <associations> collection: photo.slides.size

<associations>.build

Builds an object of the associated type without saving it. It takes a hash map of attributes for the new object as a parameter: slide.build_photo(:filename => "cat.jpg")

<associations>.create

Creates 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: slide.build_photo(:filename => "cat.jpg")

In this example, photo.slide is initialized to slide.

Attributes

<associations>

A collection of the associated objects: slide.photos[4]

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.