Module: Huberry::Sortable
- Defined in:
- lib/sortable.rb
Defined Under Namespace
Modules: InstanceMethods Classes: InvalidSortableList
Instance Method Summary (collapse)
-
- (Object) assert_sortable_list_exists!(list_name)
Raises InvalidSortableList if list_name is not a valid sortable list.
-
- (Object) sortable(options = {})
Allows you to sort items similar to github.com/rails/acts_as_list by with added support for multiple scopes and lists.
Instance Method Details
- (Object) assert_sortable_list_exists!(list_name)
Raises InvalidSortableList if list_name is not a valid sortable list
6 7 8 |
# File 'lib/sortable.rb', line 6 def assert_sortable_list_exists!(list_name) raise ::Huberry::Sortable::InvalidSortableList.new("sortable list '#{list_name}' does not exist") unless sortable_lists.has_key?(list_name.to_s) end |
- (Object) sortable(options = {})
Allows you to sort items similar to github.com/rails/acts_as_list by with added support for multiple scopes and lists
Accepts four options:
:column => The name of the column that will be used to store an item's position in the list. Defaults to :position
:conditions => Any extra constraints to use if you need to specify a tighter scope than just a foreign key. Defaults to {}
:list_name => The name of the list (this is used when calling all sortable related instance methods). Defaults to nil
:scope => A foreign key or an array of foreign keys to use as list constraints. Defaults to []
Simple example (works just like rails/acts_as_list)
class Todo < ActiveRecord::Base
# schema
# id :integer
# project_id :integer
# description :string
# position :integer
sortable :scope => :project_id
end
@todo = Todo.create(:description => 'do something', :project_id => 1)
@todo_2 = Todo.create(:description => 'do something else', :project_id => 1)
@todo_3 = Todo.create(:description => 'some other task', :project_id => 2)
@todo.position # 1
@todo_2.position # 2
@todo_3.position # 1
@todo.move_down!
@todo_2.reload
@todo.position # 2
@todo_2.position # 1
@todo_3.position # 1
Example with multiple scopes - Stories may or may not be in a sprint, but if we scoped just by :sprint_id, all stories with a nil :sprint_id
would be sorted in one giant list instead of being sorted in each of their respective projects. Specifying an
array of scopes fixes this problem.
class Story < ActiveRecord::Base
# schema
# id :integer
# project_id :integer
# sprint_id :integer
# description :string
# position :integer
sortable :scope => [:project_id, :sprint_id]
end
Example with multiple lists - Your project management software needs to allow both clients and developers to prioritize todo items separately
so that they can be discussed and reviewed during their next meeting. Multiple lists solves this problem.
class Todo < ActiveRecord::Base
# schema
# id :integer
# project_id :integer
# description :string
# client_priority :integer
# developer_priority :integer
sortable :scope => :project_id, :column => :client_priority, :list_name => :client
sortable :scope => :project_id, :column => :developer_priority, :list_name => :developer
end
@todo = Todo.create(:description => 'do something', :project_id => 1)
@todo_2 = Todo.create(:description => 'do something else', :project_id => 1)
@todo.client_priority # 1
@todo.developer_priority # 1
@todo_2.client_priority # 2
@todo_2.developer_priority # 2
@todo.move_down!(:client)
@todo_2.reload
@todo.client_priority # 2
@todo.developer_priority # 1
@todo_2.client_priority # 1
@todo_2.developer_priority # 2
Any attributes specified as a :scope that are changed on an item cause the item to automatically switch lists when it is saved
Example
class Todo < ActiveRecord::Base
# schema
# id :integer
# project_id :integer
# description :string
# position :integer
sortable :scope => :project_id
end
@todo = Todo.create(:description => 'do something', :project_id => 1)
@todo_2 = Todo.create(:description => 'do something else', :project_id => 1)
@todo.position # 1
@todo_2.position # 2
@todo.project_id = 2
@todo.save
@todo_2.reload
@todo.position # 1
@todo_2.position # 1
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/sortable.rb', line 118 def sortable( = {}) include InstanceMethods unless include?(InstanceMethods) cattr_accessor :sortable_lists unless respond_to?(:sortable_lists) self.sortable_lists ||= {} define_attribute_methods = { :column => :position, :conditions => {}, :list_name => nil, :scope => [] }.merge() [:conditions] = [:conditions].inject(['1 = 1']) do |conditions, (key, value)| conditions.first << " AND #{key.is_a?(Symbol) ? "#{table_name}.#{key}" : key} " if value.nil? conditions.first << 'IS NULL' else conditions.first << '= ?' conditions << value end end if [:conditions].is_a?(Hash) [:conditions] = Array([:conditions]) [:scope] = Array([:scope]) [:scope].each do |scope| [:conditions].first << " AND (#{table_name}.#{scope} = ?)" unless instance_methods.include?("#{scope}_with_sortable=") define_method "#{scope}_with_sortable=" do |value| sortable_scope_changes << scope unless sortable_scope_changes.include?(scope) || new_record? || value.to_s == send(scope).to_s || !self.class.sortable_lists.any? { |list_name, configuration| configuration[:scope].include?(scope) } send("#{scope}_without_sortable=".to_sym, value) end alias_method_chain "#{scope}=".to_sym, :sortable end end self.sortable_lists[.delete(:list_name).to_s] = end |