class OnlineMigrations::BackgroundMigrations::ResetCounters
@private
Attributes
counters[R]
model[R]
touch[R]
Public Class Methods
new(model_name, counters, options = {})
click to toggle source
# File lib/online_migrations/background_migrations/reset_counters.rb, line 9 def initialize(model_name, counters, options = {}) @model = Object.const_get(model_name, false) @counters = counters @touch = options[:touch] end
Public Instance Methods
count()
click to toggle source
# File lib/online_migrations/background_migrations/reset_counters.rb, line 51 def count # Exact counts are expensive on large tables, since PostgreSQL # needs to do a full scan. An estimated count should give a pretty decent # approximation of rows count in this case. Utils.estimated_count(connection, model.table_name) end
process_batch(relation)
click to toggle source
# File lib/online_migrations/background_migrations/reset_counters.rb, line 19 def process_batch(relation) updates = counters.map do |counter_association| has_many_association = has_many_association(counter_association) foreign_key = has_many_association.foreign_key.to_s child_class = has_many_association.klass reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? } counter_name = reflection.counter_cache_column quoted_association_table = connection.quote_table_name(has_many_association.table_name) count_subquery = <<-SQL.strip_heredoc SELECT COUNT(*) FROM #{quoted_association_table} WHERE #{quoted_association_table}.#{connection.quote_column_name(foreign_key)} = #{model.quoted_table_name}.#{model.quoted_primary_key} SQL "#{connection.quote_column_name(counter_name)} = (#{count_subquery})" end if touch names = touch if touch != true names = Array.wrap(names) options = names.extract_options! touch_updates = touch_attributes_with_time(*names, **options) # In ActiveRecord 4.2 sanitize_sql_for_assignment is protected updates << model.send(:sanitize_sql_for_assignment, touch_updates) end relation.update_all(updates.join(", ")) end
relation()
click to toggle source
# File lib/online_migrations/background_migrations/reset_counters.rb, line 15 def relation model.unscoped end
Private Instance Methods
connection()
click to toggle source
# File lib/online_migrations/background_migrations/reset_counters.rb, line 96 def connection model.connection end
has_many_association(counter_association)
click to toggle source
# File lib/online_migrations/background_migrations/reset_counters.rb, line 59 def has_many_association(counter_association) # rubocop:disable Naming/PredicateName has_many_association = model.reflect_on_association(counter_association) unless has_many_association has_many = model.reflect_on_all_associations(:has_many) has_many_association = has_many.find do |association| counter_cache_column = association.counter_cache_column # ActiveRecord <= 4.2 is able to return only explicitly provided `counter_cache` column. if !counter_cache_column && Utils.ar_version <= 4.2 counter_cache_column = "#{association.name}_count" end counter_cache_column && counter_cache_column.to_sym == counter_association.to_sym end counter_association = has_many_association.plural_name if has_many_association end raise ArgumentError, "'#{model.name}' has no association called '#{counter_association}'" unless has_many_association if has_many_association.is_a?(ActiveRecord::Reflection::ThroughReflection) has_many_association = has_many_association.through_reflection end has_many_association end
timestamp_attributes_for_update()
click to toggle source
# File lib/online_migrations/background_migrations/reset_counters.rb, line 92 def timestamp_attributes_for_update ["updated_at", "updated_on"].map { |name| model.attribute_aliases[name] || name } end
touch_attributes_with_time(*names, time: nil)
click to toggle source
# File lib/online_migrations/background_migrations/reset_counters.rb, line 86 def touch_attributes_with_time(*names, time: nil) attribute_names = timestamp_attributes_for_update & model.column_names attribute_names |= names.map(&:to_s) attribute_names.map { |attribute_name| [attribute_name, time || Time.current] }.to_h end