A Rails plugin that provides list abilities to an ActiveRecord model
This acts_as
extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a position
column defined as an integer on the mapped database table.
In your Gemfile:
gem 'acts_as_list'
Or, from the command line:
gem install acts_as_list
At first, you need to add a position
column to desired table:
rails g migration AddPositionToTodoItem position:integer
rake db:migrate
After that you can use acts_as_list
method in the model:
class TodoList < ActiveRecord::Base
has_many :todo_items, -> { order("position ASC") }
end
class TodoItem < ActiveRecord::Base
belongs_to :todo_list
acts_as_list scope: :todo_list
end
todo_list.first.move_to_bottom
todo_list.last.move_higher
You'll have a number of methods added to each instance of the ActiveRecord model that to which acts_as_list
is added.
In acts_as_list
, "higher" means further up the list (a lower position
), and "lower" means further down the list (a higher position
). That can be confusing, so it might make sense to add tests that validate that you're using the right method given your context.
list_item.insert_at(2)
list_item.move_lower
will do nothing if the item is the lowest itemlist_item.move_higher
will do nothing if the item is the highest itemlist_item.move_to_bottom
list_item.move_to_top
list_item.remove_from_list
list_item.increment_position
list_item.decrement_position
list_item.set_list_position(3)
list_item.first?
list_item.last?
list_item.in_list?
list_item.not_in_list?
list_item.default_position?
list_item.higher_item
list_item.higher_items
will return all the items above list_item
in the list (ordered by the position, ascending)list_item.lower_item
list_item.lower_items
will return all the items below list_item
in the list (ordered by the position, ascending)If the position
column has a default value, then there is a slight change in behavior, i.e if you have 4 items in the list, and you insert 1, with a default position 0, it would be pushed to the bottom of the list. Please look at the tests for this and some recent pull requests for discussions related to this.
All position
queries (select, update, etc.) inside gem methods are executed without the default scope (i.e. Model.unscoped
), this will prevent nasty issues when the default scope is different from acts_as_list
scope.
The position
column is set after validations are called, so you should not put a presence
validation on the position
column.
If you need a scope by a non-association field you should pass an array, containing field name, to a scope:
class TodoItem < ActiveRecord::Base
# `kind` is a plain text field (e.g. 'work', 'shopping', 'meeting'), not an association
acts_as_list scope: [:kind]
end
All versions 0.1.5
onwards require Rails 3.0.x and higher.
acts_as_list
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license