Monday, February 4, 2008

acts_as_list: Don't use ":null => false" for the position column

When using the Rails acts_as_list plugin, you must include a
"position" column for any model that is using the plugin.

In the migration for that model, I had specified the column,
preventing it from being null:

t.integer :position, :null => false

When you try to delete an item from the list, it blows up under
SQLite3 with this error:

SQLite3::SQLException: SQL logic error or missing database: UPDATE
audios SET "created_at" = '2008-02-04 16:19:47', "product_id" = 2,
"position" = NULL, ...

The plugin is removing the item from the list and setting the position
to NULL before deleting it, which causes the SQL update because of
this code:

# Removes the item from the list.
def remove_from_list
  if in_list?
    decrement_positions_on_lower_items
    update_attribute position_column, nil
  end
end

It's not a bug, but it is unexpected, because the very next SQL
command deletes that row.

It's just the nature of having the plugin be called in before_destroy:

before_destroy :remove_from_list

By the way, the acts_as_list is a great example for writing your own
plugin because it has all the Ruby language tricks required, and is
simple to understand.