diff options
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/CHANGELOG.md | 4 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/association_scope.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/builder/belongs_to.rb | 124 | ||||
-rw-r--r-- | activerecord/test/cases/locking_test.rb | 2 |
4 files changed, 83 insertions, 49 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 170084cf67..0955761b7f 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,5 @@ * Remove column restrictions for `count`, let the database raise if the SQL is - invalid. The previos behavior was untested and surprising for the user. + invalid. The previous behavior was untested and surprising for the user. Fixes #5554. Example: @@ -56,7 +56,7 @@ *Yves Senn* -* Fix bug where tiny types are incorectly coerced as booleand when the length is more than 1. +* Fix bug where tiny types are incorrectly coerced as boolean when the length is more than 1. Fixes #10620. diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index aa5551fe0c..f1bec5787a 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -96,7 +96,7 @@ module ActiveRecord item = eval_scope(klass, scope_chain_item) if scope_chain_item == self.reflection.scope - scope.merge! item.except(:where, :includes) + scope.merge! item.except(:where, :includes, :bind) end scope.includes! item.includes_values diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb index 63e9526436..d4e1a0dda1 100644 --- a/activerecord/lib/active_record/associations/builder/belongs_to.rb +++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb @@ -19,82 +19,116 @@ module ActiveRecord::Associations::Builder reflection end - def add_counter_cache_callbacks(reflection) - cache_column = reflection.counter_cache_column - foreign_key = reflection.foreign_key + def valid_dependent_options + [:destroy, :delete] + end + + private - mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1 - def belongs_to_counter_cache_after_create_for_#{name} - if record = #{name} - record.class.increment_counter(:#{cache_column}, record.id) + def add_counter_cache_methods(mixin) + return if mixin.method_defined? :belongs_to_counter_cache_after_create + + mixin.class_eval do + def belongs_to_counter_cache_after_create(association, reflection) + if record = send(association.name) + cache_column = reflection.counter_cache_column + record.class.increment_counter(cache_column, record.id) @_after_create_counter_called = true end end - def belongs_to_counter_cache_before_destroy_for_#{name} - unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == #{foreign_key.to_sym.inspect} - record = #{name} + def belongs_to_counter_cache_before_destroy(association, reflection) + foreign_key = reflection.foreign_key.to_sym + unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key + record = send association.name if record && !self.destroyed? - record.class.decrement_counter(:#{cache_column}, record.id) + cache_column = reflection.counter_cache_column + record.class.decrement_counter(cache_column, record.id) end end end - def belongs_to_counter_cache_after_update_for_#{name} + def belongs_to_counter_cache_after_update(association, reflection) + foreign_key = reflection.foreign_key + cache_column = reflection.counter_cache_column + if (@_after_create_counter_called ||= false) @_after_create_counter_called = false - elsif self.#{foreign_key}_changed? && !new_record? && defined?(#{name.to_s.camelize}) - model = #{name.to_s.camelize} - foreign_key_was = self.#{foreign_key}_was - foreign_key = self.#{foreign_key} + elsif attribute_changed?(foreign_key) && !new_record? && association.constructable? + model = reflection.klass + foreign_key_was = attribute_was foreign_key + foreign_key = attribute foreign_key if foreign_key && model.respond_to?(:increment_counter) - model.increment_counter(:#{cache_column}, foreign_key) + model.increment_counter(cache_column, foreign_key) end if foreign_key_was && model.respond_to?(:decrement_counter) - model.decrement_counter(:#{cache_column}, foreign_key_was) + model.decrement_counter(cache_column, foreign_key_was) end end end - CODE + end + end + + def add_counter_cache_callbacks(reflection) + cache_column = reflection.counter_cache_column + add_counter_cache_methods mixin + association = self + + model.after_create lambda { |record| + record.belongs_to_counter_cache_after_create(association, reflection) + } - model.after_create "belongs_to_counter_cache_after_create_for_#{name}" - model.before_destroy "belongs_to_counter_cache_before_destroy_for_#{name}" - model.after_update "belongs_to_counter_cache_after_update_for_#{name}" + model.before_destroy lambda { |record| + record.belongs_to_counter_cache_before_destroy(association, reflection) + } + + model.after_update lambda { |record| + record.belongs_to_counter_cache_after_update(association, reflection) + } klass = reflection.class_name.safe_constantize klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly) end - def add_touch_callbacks(reflection) - mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1 - def belongs_to_touch_after_save_or_destroy_for_#{name} - foreign_key_field = #{reflection.foreign_key.inspect} - old_foreign_id = attribute_was(foreign_key_field) + def self.touch_record(o, foreign_key, name, touch) # :nodoc: + old_foreign_id = o.attribute_was(foreign_key) - if old_foreign_id - klass = association(#{name.inspect}).klass - old_record = klass.find_by(klass.primary_key => old_foreign_id) + if old_foreign_id + klass = o.association(name).klass + old_record = klass.find_by(klass.primary_key => old_foreign_id) - if old_record - old_record.touch #{options[:touch].inspect if options[:touch] != true} - end - end - - record = #{name} - unless record.nil? || record.new_record? - record.touch #{options[:touch].inspect if options[:touch] != true} + if old_record + if touch != true + old_record.touch touch + else + old_record.touch end end - CODE - - model.after_save "belongs_to_touch_after_save_or_destroy_for_#{name}" - model.after_touch "belongs_to_touch_after_save_or_destroy_for_#{name}" - model.after_destroy "belongs_to_touch_after_save_or_destroy_for_#{name}" + end + + record = o.send name + unless record.nil? || record.new_record? + if touch != true + record.touch touch + else + record.touch + end + end end - def valid_dependent_options - [:destroy, :delete] + def add_touch_callbacks(reflection) + foreign_key = reflection.foreign_key + n = name + touch = options[:touch] + + callback = lambda { |record| + BelongsTo.touch_record(record, foreign_key, n, touch) + } + + model.after_save callback + model.after_touch callback + model.after_destroy callback end end end diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 77891b9156..0030f1b464 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -242,7 +242,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase car = Car.create! assert_difference 'car.wheels.count' do - car.wheels << Wheel.create! + car.wheels << Wheel.create! end assert_difference 'car.wheels.count', -1 do car.destroy |