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(old_list, 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
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/active_sorting/model.rb', line 91 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
76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/active_sorting/model.rb', line 76 def active_sorting_changes_required(old_list, new_list) raise Exceptions::InvalidListSize, "Sortable new and old lists should be of the same length" if old_list.count != new_list.count changes = [] 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
52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/active_sorting/model.rb', line 52 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
43 44 45 46 47 48 49 |
# File 'lib/active_sorting/model.rb', line 43 def { order: :asc, step: 500, scope: [] } end |
#active_sorting_default_scope ⇒ Object
66 67 68 69 70 |
# File 'lib/active_sorting/model.rb', line 66 def active_sorting_default_scope conditions = {} conditions[active_sorting_field] = active_sorting_order order(conditions) end |
#active_sorting_field ⇒ Object
130 131 132 |
# File 'lib/active_sorting/model.rb', line 130 def active_sorting_field [:name] end |
#active_sorting_find_by(id_column, value) ⇒ Object
146 147 148 149 150 |
# File 'lib/active_sorting/model.rb', line 146 def active_sorting_find_by(id_column, value) conditions = {} conditions[id_column] = value find_by(conditions) end |
#active_sorting_make_changes(old_list, new_list, changes, id_column) ⇒ Object
Commit changes to database
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/active_sorting/model.rb', line 107 def active_sorting_make_changes(old_list, 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 = 0 n2 = active_sorting_find_by(id_column, old_list[index]).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
138 139 140 |
# File 'lib/active_sorting/model.rb', line 138 def active_sorting_order [:order] end |
#active_sorting_scope ⇒ Object
142 143 144 |
# File 'lib/active_sorting/model.rb', line 142 def active_sorting_scope [:scope] end |
#active_sorting_step ⇒ Object
134 135 136 |
# File 'lib/active_sorting/model.rb', line 134 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 |
# File 'lib/active_sorting/model.rb', line 33 def sort_list(new_list, id_column = :id) raise ArgumentError, "Sortable list should not be empty" if new_list.empty? conditions = { id_column => new_list } old_list = unscoped.active_sorting_default_scope.where(conditions).pluck(id_column) raise Exceptions::RecordsNotFound, "Sortable list should be persisted to database with #{name} Model" if old_list.empty? changes = active_sorting_changes_required(old_list, new_list) active_sorting_make_changes(old_list, 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 |