Active Record has three special relationships that let you
explicitly model lists, trees, and nested sets: acts_as_list
, acts_as_tree
, and acts_as_nested_set
, respectively. We’ll look at
the two relationships required by Photo Share in this chapter: acts_as_list
and acts_as_tree
. acts_as_list
lets you
express items as an ordered list and also provides methods to move items
around in the hierarchy. Figure 4-5 shows
the mapping. In Photo Share, we’ll use acts_as_list
to model a slideshow, which is an
ordered list of slides. Later, we’ll use acts_as_tree
to manage our nested
categories.
First, let’s modify the existing
app/models/slide.rb model. We want users to be able
to move slides up and down in a show, so the slideshow needs an ordering.
We’ll use the existing slides and add the Active Record macro acts_as_list
.
class Slide < ActiveRecord::Base belongs_to :slideshow belongs_to :photo acts_as_list :scope => "slideshow_id" end
This example builds a list of slides that compose a slideshow.
belongs_to
is a one-to-many
relationship, imposing structure. The Slide
model has a belongs_to
relationship with Slideshow
and Photo
as the targets. acts_as_list
is a helper macro, imposing order
and introducing behavior related to a list. As of Rails 2.0, the macro is
a plug-in and not part of the base library. To get it, type:
script/plugin install acts_as_list
.
$ script/plugin install acts_as_list + ./README + ./init.rb + ./lib/active_record/acts/list.rb + ./test/list_test.rb
That command loads the acts_as_list
plug-in into the
vendor/plugins/acts_as_list directory. From that
point, you can use it just as if it were a native Rails macro. To Active
Record, each macro is independent. You use the :scope
parameter to tell Active Record which
items belong in the list. In this case, we set the :scope
parameter to :slideshow_id
so all slides with the same
slideshow_id
will
act as one independent list.
To capture ordering, Active Record uses a position
attribute by default. Because you have
a position column in the database, you don’t need to do anything more to
the slides to support this list. However, for convenience, you’ll want the
array of slides to be fetched and displayed in the right order, so make
one small change to app/models/slideshow.rb
:
class Slideshow < ActiveRecord::Base has_many :slides, :order => :position end
We’re ready to use the list. You can use methods added by acts_as_list
to change the order of slides in
the slideshow, and to indicate which items are first and last:
>> show = Slideshow.find 1 => #<Slideshow id: 1, name: "Interesting Pictures", created_at: "2008-05-11 00:37:27", updated_at: "2008-05-11 00:37:27"> >> show.slides.each {|slide| puts slide.photo.filename} train.jpg lighthouse.jpg gargoyle.jpg cat.jpg cappucino.jpg building.jpg bridge.jpg bear.jpg baskets.jpg => [#<Slide id: 1, ...] >> show.slides.first.photo.filename => "train.jpg" >> show.slides.first.move_to_bottom => true >> show.slides.last.photo.filename => "baskets.jpg" >> show.reload => #<Slideshow id: 1, name: "Interesting Pictures", created_at: "2008-05-21 02:19:32", updated_at: "2008-05-21 02:19:32"> >> show.slides => [#<Slide id: 2, ...>, ...] >> show.slides.last.photo.filename => "train.jpg"
By convention, positions start at 1 and are sequentially numbered through the end of the list. Position 1 is the top, and the biggest number is the bottom. You can move any item higher or lower, move items to the top or bottom, create items in any position, and get relative items in the list, as in Table 4-3. Keep in mind that moving something higher means making the position smaller, so you should think of the position as a priority. Higher positions mean higher priorities, so they’ll be closer to the front of the list.
Table 4-3 shows all the methods
added by the acts_as_list
relationship.
Keep in mind that you’ll use acts_as_list
on objects that already have a
belongs_to
relationship, so you’ll also
get the methods and attributes provided by belongs_to
. You’ll also inherit the methods from
the array, so slideshow.slides[1]
and
slideshow.slides.first
are both
legal.
Table 4-3. Metaprogramming features for acts_as_list
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.