Module: ActiveRecord::Acts::List::ClassMethods
- Defined in:
- lib/acts_as_list/active_record/acts/list.rb
Overview
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.
Todo list example:
class TodoList < ActiveRecord::Base
has_many :todo_items, order: "position"
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
Instance Method Summary collapse
-
#acts_as_list(options = {}) ⇒ Object
Configuration options are:.
Instance Method Details
#acts_as_list(options = {}) ⇒ Object
Configuration options are:
-
column- specifies the column name to use for keeping the position integer (default:position) -
scope- restricts what is to be considered a list. Given a symbol, it’ll attach_id(if it hasn’t already been added) and use that as the foreign key restriction. It’s also possible to give it an entire string that is interpolated if you need a tighter scope than just a foreign key. Example:acts_as_list scope: 'todo_list_id = #{todo_list_id} AND completed = 0' -
top_of_list- defines the integer used for the top of the list. Defaults to 1. Use 0 to make the collection act more like an array in its indexing. -
add_new_at- specifies whether objects get added to the :top or :bottom of the list. (default:bottom)`nil` will result in new items not being added to the list on create
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 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 154 155 156 157 158 159 |
# File 'lib/acts_as_list/active_record/acts/list.rb', line 37 def acts_as_list( = {}) configuration = { column: "position", scope: "1 = 1", top_of_list: 1, add_new_at: :bottom} configuration.update() if .is_a?(Hash) if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/ configuration[:scope] = :"#{configuration[:scope]}_id" end caller_class = self class_eval do define_singleton_method :acts_as_list_top do configuration[:top_of_list].to_i end define_method :acts_as_list_top do configuration[:top_of_list].to_i end define_method :acts_as_list_class do caller_class end define_method :position_column do configuration[:column] end define_method :scope_name do configuration[:scope] end define_method :add_new_at do configuration[:add_new_at] end define_method :"#{configuration[:column]}=" do |position| write_attribute(configuration[:column], position) @position_changed = true end if configuration[:scope].is_a?(Symbol) define_method :scope_condition do { configuration[:scope] => send(:"#{configuration[:scope]}") } end define_method :scope_changed? do changed.include?(scope_name.to_s) end elsif configuration[:scope].is_a?(Array) define_method :scope_condition do configuration[:scope].inject({}) do |hash, column| hash.merge!({ column.to_sym => read_attribute(column.to_sym) }) end end define_method :scope_changed? do (scope_condition.keys & changed.map(&:to_sym)).any? end else define_method :scope_condition do eval "%{#{configuration[:scope]}}" end define_method :scope_changed? do false end end # only add to attr_accessible # if the class has some mass_assignment_protection if defined?(accessible_attributes) and !accessible_attributes.blank? attr_accessible :"#{configuration[:column]}" end define_singleton_method :quoted_position_column do @_quoted_position_column ||= connection.quote_column_name(configuration[:column]) end define_singleton_method :quoted_position_column_with_table_name do @_quoted_position_column_with_table_name ||= "#{caller_class.quoted_table_name}.#{quoted_position_column}" end scope :in_list, lambda { where("#{quoted_position_column_with_table_name} IS NOT NULL") } define_singleton_method :decrement_all do update_all_with_touch "#{quoted_position_column} = (#{quoted_position_column_with_table_name} - 1)" end define_singleton_method :increment_all do update_all_with_touch "#{quoted_position_column} = (#{quoted_position_column_with_table_name} + 1)" end define_singleton_method :update_all_with_touch do |updates| record = new attrs = record.send(:timestamp_attributes_for_update_in_model) now = record.send(:current_time_from_proper_timezone) query = attrs.map { |attr| "#{connection.quote_column_name(attr)} = :now" } query.push updates query = query.join(", ") update_all([query, now: now]) end end attr_reader :position_changed before_validation :check_top_position before_destroy :lock! after_destroy :decrement_positions_on_lower_items before_update :check_scope after_update :update_positions after_commit :clear_scope_changed if configuration[:add_new_at].present? before_create "add_to_list_#{configuration[:add_new_at]}".to_sym end include ::ActiveRecord::Acts::List::InstanceMethods end |