• Skip to main content
  • Skip to secondary menu
  • Skip to primary sidebar

FromThePage Blog

Crowdsourcing, transcription and indexing for libraries and archives

  • Home
  • Interviews
  • crowdsourcing
  • how-to
  • Back to FromThePage
  • Collections

Rails: acts_as_list Incantations

June 2, 2007 by Ben Brumfield

In my experience, really great software is so consistent that when you're trying to do something you've never done before, you can guess at how it's done and at least half of the time, it just works. For the most part, Ruby on Rails is like that. There are best practices baked into the framework for processes I never even realized you could have best practices for, like the unpleasant but necessary task of writing upgrade scripts. Through Rails, I've learned CS concepts like optimistic locking that were entirely new to me, and used them effectively after an hour's study and a dozen lines of code.

So it's disappointing and almost a little surprising when I encounter a feature of the Rails framework that doesn't just work automatically. acts_as_list is such a feature, requiring days of reading source files and experimenting with logfile to figure out the series of magical incantations needed to make the darn thing work.

The theory behind acts_as_list is pretty simple. You add an integer position column to a database table, and add acts_as_list to the model class it maps to. At that point, anytime you use the object in a collection, the position column gets set with the sort order of that object relative to everything else in the collection. List order is even scoped: a child table can be ordered within the context of its parent table by adding :scope => :parent_model_name to the model declaration.

In practice, however, there are some problems I ran into which I wasn't expecting. Some of them are well documented in Agile Web Development with Rails, but some of them required a great deal of research to solve.

List items appear in order of record creation, not in order of :position

If an ImageSet has_many TitledImages, and TitledImage acts_as_list over the scope of an ImageSet, you'd expect ImageSet.titled_images to return a collection in the order that's set in the position column, right? This won't happen unless you modify the parent class definition (ImageSet, in this case) to specify an order column on your has_many declaration:
has_many :titled_images, :order => :position

Pagination loses list order

Having fixed this problem, if you page through a list of items, you'll discover that the items once again appear in order of record creation, ignoring the value set in position. Fixing this requires you to manually specify the order for paged items using the :order option to paginate:

    @image_pages, @titled_images = paginate(:titled_image,
                                          {:per_page => 10,
                                           :conditions => conditions,
                                           :order => 'position' })

Adjusting list order doesn't update objects in memory

Okay, this one took me the most time to figure out. acts_as_list has nothing to do with the order of your collection. Using array operators to move elements around in the collection returned by ImageSet.titled_image does absolutely nothing to the position column.

Worse yet, using the acts_as_list position modifiers like insert_at will not affect the objects in memory. So if you've been working with a collection, then call an acts_as_list method that affects its position, saving the elements that of collection will overwrite the position with old values. The position manipulation operators are designed to minimize SQL statements executed: among other side-effects, they circumvent optimistic locking. You must reload your collections after doing any list manipulation.

Moving list items from one parent object to another doesn't reorder their positions

Because acts_as_list pays little attention to order within a collection, removing an item from one parent and adding it to another requires explicit updates to the position attribute. You should probably use remove_from_list to zero out the position before you transfer items from one parent to another, but since this reshuffles position columns for all other items in the list, I'd be cautious about doing this within a loop. Since I was collating items from two different lists into a third, I just manually set the position:

    0.upto(max_size-1) do |i|
    # append the left element here
    if i < left_size
      new_set.titled_images << left_set.titled_images[i]
    end
    # append the right element
    if i < right_size
      new_set.titled_images << right_set.titled_images[i]
    end
  end
  # this has no effect on acts as list unless I do it manually
  1.upto(new_set.titled_images.size) do |i|
    new_set.titled_images[i-1].position=i
  end

In my opinion, acts_as_list is still worth using — in fact, I'm about to work with its reordering functionality a lot. But I won't be surprised if I find myself experimenting with logfiles again.

Filed Under: rails

Reader Interactions

Comments

  1. Anonymous says

    January 18, 2008 at 7:35 pm

    Man, I’m glad I found this — thanks!

  2. iFactoryOutlet says

    March 20, 2008 at 7:44 pm

    this is true, plugins that help with collections have some unexpected side effects when they aren’t updating the database when you expect it to. I’ve resorted to doing a collection reload whenever I make a change to the list, to make sure I’m looking at the freshest copy from the database. Not the most elegant method I know. I should probably dig more into the source and figure out a better way.

    Henry
    Rain Hats

  3. Melissa says

    January 6, 2009 at 2:39 am

    looks like you need to install a plugin to use it these days:
    ruby scriptplugin install git://github.com/rails/acts_as_list.git

  4. Thomas Stalcup Jr (TJ) says

    January 21, 2010 at 8:48 pm

    wow thanks melissa, that helped alot!

Primary Sidebar

What’s Trending on The FromThePage Blog

  • What to Do When Your Transcribers Can’t Read Cursive
  • Classifying the Mistakes We Make When We Transcribe
  • 10 Ways AI Will Change Archives
  • Learn to Decipher Old Handwriting with Online and…
  • Animatronic GPTs at Museums?
  • Project Profile: Stanford University Archives

Recent Client Interviews

An Interview with Candice Cloud of Stephen F. Austin State University

An Interview with Shanna Raines of the Greenville County Library System

An Interview with Jodi Hoover of Digital Maryland

An Interview with Michael Lapides of the New Bedford Whaling Museum

An Interview with NC State University Libraries

Read More

ai artificial intelligence crowdsourcing features fromthepage projects handwriting history iiif indexing Indianapolis Indianapolis Children's Museum interview Jennifer Noffze machine learning metadata ocr paleography podcast racism Ryan White spreadsheet transcription transcription transcription software

Copyright © 2025 · Magazine Pro on Genesis Framework · WordPress · Log in

Want more content like this?  We publish a newsletter with interesting thought pieces on transcripion and AI for archives once a month.


By signing up, you agree to our Privacy Policy and Terms of Service. We may send you occasional newsletters and promotional emails about our products and services. You can opt-out at any time.  We never sell your information.