Class: CounterCulture::Reconciler::Reconciliation
- Inherits:
-
Object
- Object
- CounterCulture::Reconciler::Reconciliation
- Defined in:
- lib/counter_culture/reconciler.rb
Instance Attribute Summary collapse
-
#counter ⇒ Object
readonly
Returns the value of attribute counter.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#relation_class ⇒ Object
readonly
Returns the value of attribute relation_class.
Instance Method Summary collapse
-
#initialize(counter, changes_holder, options, relation_class) ⇒ Reconciliation
constructor
A new instance of Reconciliation.
- #perform ⇒ Object
Constructor Details
#initialize(counter, changes_holder, options, relation_class) ⇒ Reconciliation
61 62 63 64 65 |
# File 'lib/counter_culture/reconciler.rb', line 61 def initialize(counter, changes_holder, , relation_class) @counter, , = counter, @relation_class = relation_class @changes_holder = changes_holder end |
Instance Attribute Details
#counter ⇒ Object (readonly)
Returns the value of attribute counter.
56 57 58 |
# File 'lib/counter_culture/reconciler.rb', line 56 def counter @counter end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
56 57 58 |
# File 'lib/counter_culture/reconciler.rb', line 56 def end |
#relation_class ⇒ Object (readonly)
Returns the value of attribute relation_class.
56 57 58 |
# File 'lib/counter_culture/reconciler.rb', line 56 def relation_class @relation_class end |
Instance Method Details
#perform ⇒ Object
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 |
# File 'lib/counter_culture/reconciler.rb', line 67 def perform # if we're provided a custom set of column names with conditions, use them; just use the # column name otherwise # which class does this relation ultimately point to? that's where we have to start scope = relation_class counter_column_names = column_names || {nil => counter_cache_name} # iterate over all the possible counter cache column names counter_column_names.each do |where, column_name| # if the column name is nil, that means those records don't affect # counts; we don't need to do anything in that case. but we allow # specifying that condition regardless to make the syntax less # confusing next unless column_name # select join column and count (from above) as well as cache column ('column_name') for later comparison counts_query = scope.select("#{relation_class.table_name}.#{relation_class.primary_key}, #{relation_class.table_name}.#{relation_reflect(relation).association_primary_key(relation_class)}, #{count_select} AS count, #{relation_class.table_name}.#{column_name}") # we need to join together tables until we get back to the table this class itself lives in # conditions must also be applied to the join on which we are counting join_clauses.each_with_index do |join, index| if index == join_clauses.size - 1 if where join += " AND (#{model.send(:sanitize_sql_for_conditions, where)})" end # respect the deleted_at column if it exists if model.column_names.include?('deleted_at') join += " AND #{model.table_name}.deleted_at IS NULL" end end counts_query = counts_query.joins(join) end # iterate in batches; otherwise we might run out of memory when there's a lot of # instances and we try to load all their counts at once batch_size = .fetch(:batch_size, CounterCulture.config.batch_size) counts_query.group(full_primary_key(relation_class)).find_in_batches(batch_size: batch_size) do |records| # now iterate over all the models and see whether their counts are right ActiveRecord::Base.transaction do records.each do |record| count = record.read_attribute('count') || 0 next if record.read_attribute(column_name) == count track_change(record, column_name, count) # use update_all because it's faster and because a fixed counter-cache shouldn't update the timestamp relation_class.where(relation_class.primary_key => record.send(relation_class.primary_key)).update_all(column_name => count) end end end end end |