Rails Acts_as_List Declaration

The acts_as_list declaration in Rails is useful little device which doesn't have an obvious counterpart in Cocoa/Core Data. It also tickles some of the side effects of Rails being more SQL-centric than Core Data, which honestly caused some confusion for me initially.

Essentially, acts_as_list uses a column to maintain a position in a list, transparently adding methods to an object:
item.move_lower
item.move_higher
item.move_to_top
item.higher_item
item.first?
...


There are number of useful tools here that really simplify list programming. By default, Rails uses a column named position to do the list management. In the O'Reilly Rails book, the Slide class looks like this:

class Slide < ActiveRecord::Base
  belongs_to :slideshow
  acts_as_list :scope => "slideshow_id"
  belongs_to :photo
end


The first SQL-centric thing that comes up here is that the list behavior is declared by Slide itself. Intuitively, I would expect Slideshow to contain this declaration, but it makes sense that Slide declares it when you consider an ActiveRecord class wraps the table itself.

That's one of the single biggest conceptual differences between Core Data and Rails. Core Data models entities which map to database tables in whatever way the framework thinks the most sense. In fact, you may not even use a database. Rails models database tables directly, which is why there's a distinction between has_one and belongs_to. In Core Data, there are only two kinds of relationships: to-many or to-one.

The SQL-centric design also comes into play when moving list items around. For example, while playing with the examples in the O'Reilly book, I added a method to Slideshow which displays the positions of Slides and the file names of their referenced photos:
def display_slides_info
  self.slides.each do |slide|
    puts "#{slide.position} Name: #{slide.photo.filename}"
  end
end


In the Rails console (a fantastic tool, by the way) I can see how things are setup:
>> show = Slideshow.find 1
...
>> show.display_slides_info
1 Name: stairs.jpg
2 Name: balboa_park.jpg
3 Name: camel.jpg
4 Name: cat_and_candles.jpg
5 Name: hut.jpg
6 Name: mosiac.jpg
7 Name: polar_bear.jpg
8 Name: police.jpg
9 Name: sleeping_dog.jpg


Now I'll change the ordering by using the move_to_bottom method, defined by the acts_as_list declaration:
>> show.slides.first.move_to_bottom
=> true
>> show.display_slides_info
9 Name: stairs.jpg
2 Name: balboa_park.jpg
3 Name: camel.jpg
4 Name: cat_and_candles.jpg
5 Name: hut.jpg
6 Name: mosiac.jpg
7 Name: polar_bear.jpg
8 Name: police.jpg
9 Name: sleeping_dog.jpg
...


At this point, there are two items in the slides array which have the same position. This won't change until I reload:

>> show.reload
...
>> show.display_slides_info
1 Name: balboa_park.jpg
2 Name: camel.jpg
3 Name: cat_and_candles.jpg
4 Name: hut.jpg
5 Name: mosiac.jpg
6 Name: polar_bear.jpg
7 Name: police.jpg
8 Name: sleeping_dog.jpg
9 Name: stairs.jpg


After the items are re-fetched from the database, everything is in the correct order. This actually confused me initially, then I realized what the difference is: there's no managed object context in Rails. The database is where the data lives.

Rails will kindly go and update all of the relative positions for the slides (which Core Data does not do), but the full story here is that the update won't be complete until the slideshow is reloaded from the database.

I'm used to thinking in terms of the Managed Object Context being the only thing that matters. Whether or not the data has been written to disk and re-fetched is largely irrelevant (by design). Sort descriptors handle the ordering and that's often managed at the view level.

As far as I can tell, since there's no equivalent to a managed object context, there's no way to rollback the changes to a list. However, property values that are changed manually won't be applied to the database until the update method is called. In that sense, you can rollback an individual object. You can also group changes (and presumably reverse them) using a transaction.

Maybe you can wrap list changes in a transaction if you want the option to revert them?
Design Element
Rails Acts_as_List Declaration
Posted Dec 30, 2006 — 3 comments below




 

Craig Hockenberry — Dec 30, 06 2958

In typical usage, a managed object context for Rails wouldn't be that useful. In a stateless HTTP request, objects are typically created and deleted within a short period of time. Your example in the Rails console is atypical: after you finish the move, your request would be complete and you'd destroy the show object. The next request would load a new show object.

The typical Cocoa application, on the other hand, has a much longer object lifecycle and benefits from a context in which objects are managed for you.

-ch

Scott Stevenson — Dec 30, 06 2959 Scotty the Leopard

The next request would load a new show object
Good point.

roger — Jan 05, 09 6585

looks like you need to install it as a plugin now:
ruby script\plugin install git://github.com/rails/acts_as_list.git




 

Comments Temporarily Disabled

I had to temporarily disable comments due to spam. I'll re-enable them soon.





Copyright © Scott Stevenson 2004-2015