Module: ActiveSorting::Model::ClassMethods
- Defined in:
- lib/active_sorting/model.rb
Overview
Patches ActiveRecord models
Instance Method Summary collapse
-
#active_sorting_calculate_changes(old_list, new_list, changes = []) ⇒ Object
Calculate the possible changes required to reorder items in
old_listto matchnew_listorder. -
#active_sorting_changes_required(old_list, new_list) ⇒ Object
Calculate the least possible changes required to reorder items in
old_listto matchnew_listorder by comparing two proposals fromactive_sorting_calculate_changes. -
#active_sorting_check_options ⇒ Object
Check provided options.
-
#active_sorting_default_options ⇒ Object
Default sorting options.
- #active_sorting_default_scope ⇒ Object
- #active_sorting_field ⇒ Object
- #active_sorting_find_by(id_column, value) ⇒ Object
-
#active_sorting_make_changes(new_list, changes, id_column) ⇒ Object
Commit changes to database.
- #active_sorting_order ⇒ Object
- #active_sorting_scope ⇒ Object
- #active_sorting_step ⇒ Object
-
#sort_list(new_list, id_column = :id) ⇒ Object
Sorts and updates the database with the given list of items in the given order.
-
#sortable(name, opts = {}) ⇒ Object
Sets the sortable options.
Instance Method Details
#active_sorting_calculate_changes(old_list, new_list, changes = []) ⇒ Object
Calculate the possible changes required to reorder items in old_list to match new_list order
94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/active_sorting/model.rb', line 94 def active_sorting_calculate_changes(old_list, new_list, changes = []) new_list.each_with_index do |id, index| next unless old_list[index] != id # This item has changed changes << id # Remove it from both lists, rinse and repeat new_list.delete(id) old_list.delete(id) # Recur... active_sorting_calculate_changes(old_list, new_list, changes) break end changes end |
#active_sorting_changes_required(old_list, new_list) ⇒ Object
Calculate the least possible changes required to reorder items in old_list to match new_list order by comparing two proposals from active_sorting_calculate_changes
77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/active_sorting/model.rb', line 77 def active_sorting_changes_required(old_list, new_list) changes = [] if old_list.count != new_list.count raise ArgumentError, "Sortable new and old lists should be of the same length" end proposal1 = active_sorting_calculate_changes(old_list.dup, new_list.dup) if proposal1.count >= (new_list.count / 4) proposal2 = active_sorting_calculate_changes(old_list.dup.reverse, new_list.dup.reverse) changes = proposal1.count < proposal2.count ? proposal1 : proposal2 else changes = proposal1 end changes end |
#active_sorting_check_options ⇒ Object
Check provided options
53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/active_sorting/model.rb', line 53 def # TODO: columns_hash breaks when database has no tables # field_type = columns_hash[active_sorting_field.to_s].type # unless field_type == :integer # raise ArgumentError, "Sortable field should be of type Integer, #{field_type} where given" # end unless active_sorting_step.is_a?(Fixnum) raise ArgumentError, "Sortable step should be of type Fixnum, #{active_sorting_step.class.name} where given" end unless active_sorting_scope.respond_to?(:each) raise ArgumentError, "Sortable step should be of type Enumerable, #{active_sorting_scope.class.name} where given" end end |
#active_sorting_default_options ⇒ Object
Default sorting options
44 45 46 47 48 49 50 |
# File 'lib/active_sorting/model.rb', line 44 def { order: :asc, step: 500, scope: [] } end |
#active_sorting_default_scope ⇒ Object
67 68 69 70 71 |
# File 'lib/active_sorting/model.rb', line 67 def active_sorting_default_scope conditions = {} conditions[active_sorting_field] = active_sorting_order order(conditions) end |
#active_sorting_field ⇒ Object
133 134 135 |
# File 'lib/active_sorting/model.rb', line 133 def active_sorting_field [:name] end |
#active_sorting_find_by(id_column, value) ⇒ Object
149 150 151 152 153 |
# File 'lib/active_sorting/model.rb', line 149 def active_sorting_find_by(id_column, value) conditions = {} conditions[id_column] = value find_by(conditions) end |
#active_sorting_make_changes(new_list, changes, id_column) ⇒ Object
Commit changes to database
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/active_sorting/model.rb', line 110 def active_sorting_make_changes(new_list, changes, id_column) new_list.each_with_index do |id, index| next unless changes.include?(id) if index == new_list.count.pred # We're moving an item to last position, # increase the count of last item's position # by the step n1 = active_sorting_find_by(id_column, new_list[index.pred]).active_sorting_value n2 = n1 + active_sorting_step elsif index == 0 # We're moving an item to first position # Calculate the gap between following 2 items n1 = active_sorting_find_by(id_column, new_list[index.next]).active_sorting_value n2 = active_sorting_find_by(id_column, new_list[index.next]).active_sorting_value else # We're moving a non-terminal item n1 = active_sorting_find_by(id_column, new_list[index.pred]).active_sorting_value n2 = active_sorting_find_by(id_column, new_list[index.next]).active_sorting_value end active_sorting_find_by(id_column, id).active_sorting_center_item(n1, n2) end end |
#active_sorting_order ⇒ Object
141 142 143 |
# File 'lib/active_sorting/model.rb', line 141 def active_sorting_order [:order] end |
#active_sorting_scope ⇒ Object
145 146 147 |
# File 'lib/active_sorting/model.rb', line 145 def active_sorting_scope [:scope] end |
#active_sorting_step ⇒ Object
137 138 139 |
# File 'lib/active_sorting/model.rb', line 137 def active_sorting_step [:step] end |
#sort_list(new_list, id_column = :id) ⇒ Object
Sorts and updates the database with the given list of items in the given order.
new_list List of ids of records in the desired order id_column the field used for fetching records from the databse,
defaults to :id
33 34 35 36 37 38 39 40 41 |
# File 'lib/active_sorting/model.rb', line 33 def sort_list(new_list, id_column = :id) raise ArgumentError, "Sortable list should not be empty" unless new_list.count conditions = {} conditions[id_column] = new_list old_list = unscoped.where(conditions).pluck(id_column) raise ArgumentError, "Sortable list should be persisted to database" unless old_list.count changes = active_sorting_changes_required(old_list, new_list) active_sorting_make_changes(new_list, changes, id_column) end |
#sortable(name, opts = {}) ⇒ Object
Sets the sortable options
name sortable field name Accepts a Hash of options: order sorting direction, defaults to :asc step stepping value, defaults to 500 scope scope field name, defaults to []
18 19 20 21 22 23 24 25 |
# File 'lib/active_sorting/model.rb', line 18 def sortable(name, opts = {}) self. = .merge(opts) [:name] = name validates [:name], presence: true default_scope { active_sorting_default_scope } before_validation :active_sorting_callback_before_validation end |