Rails acts_as_list with Soft Delete

2014-12-23

Two really useful gems for a Rails project are acts_as_list and permanent_records (or the somewhat more common acts_as_paranoid). The first one, acts_as_list, adds a position column to your model to provide natural ordering. Usually you don’t want global ordering, but only within an owning model, e.g. the Page objects inside a Book have position 1, 2, 3, and the Page objects inside a different Book also go 1, 2, 3. You can use the scope option to achieve that:

class Page
  belongs_to :book
  acts_as_list scope: :book
end

The problem is that if you are soft-deleting pages using a deleted_at column, acts_as_list doesn’t know to exclude deleted pages from the list. This gets annoying if you want to move pages up and down: Imagine you have page 1, then 5 deleted pages, and now you add a new page p to the end. You want to move your new page to the beginning. You have a button that calls p.move_higher, but the page won’t appear to move until the user presses the button five times. That is pretty confusing!

Fortunately acts_as_list lets you pass a string to scope that it will evaluate when necessary, and you can even embed Ruby code in it. Look at this, and notice the single quotes!:

class Page
  belongs_to :book
  acts_as_list scope: 'book_id = #{book_id} AND deleted_at IS NULL'
end

With that code, acts_as_list will only consider non-deleted pages, so moving a page works as it should.

blog comments powered by Disqus Prev: Postgres \copy from stdin vs pstdin Next: Postgres CTE for Threaded Comments