From eebcebdeb58ff7b6c05cb1cfbbc9aa4c85c9800e Mon Sep 17 00:00:00 2001 From: Piotr Jakubowski Date: Wed, 20 Jan 2016 21:53:17 +0100 Subject: When deleting through records, take into account association conditions Fixes #18424. When deleting through records, it didn't take into account the conditions that may have been affecting join model table, but was defined in association definition. --- .../associations/has_many_through_association.rb | 17 +++++++++-------- .../associations/has_many_through_associations_test.rb | 16 ++++++++++++++++ activerecord/test/models/author.rb | 3 +++ 3 files changed, 28 insertions(+), 8 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 36fc381343..5182a9b39d 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -132,26 +132,27 @@ module ActiveRecord scope = through_association.scope scope.where! construct_join_attributes(*records) + scope_with_association_conditions = scope.where through_scope_attributes case method when :destroy - if scope.klass.primary_key - count = scope.destroy_all.length + if scope_with_association_conditions.klass.primary_key + count = scope_with_association_conditions.destroy_all.length else - scope.each(&:_run_destroy_callbacks) + scope_with_association_conditions.each(&:_run_destroy_callbacks) - arel = scope.arel + arel = scope_with_association_conditions.arel stmt = Arel::DeleteManager.new - stmt.from scope.klass.arel_table + stmt.from scope_with_association_conditions.klass.arel_table stmt.wheres = arel.constraints - count = scope.klass.connection.delete(stmt, 'SQL', scope.bound_attributes) + count = scope_with_association_conditions.klass.connection.delete(stmt, 'SQL', scope_with_association_conditions.bound_attributes) end when :nullify - count = scope.update_all(source_reflection.foreign_key => nil) + count = scope_with_association_conditions.update_all(source_reflection.foreign_key => nil) else - count = scope.delete_all + count = scope_with_association_conditions.delete_all end delete_through_records(records) diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index aff0dabee7..888f1a14d1 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -1215,4 +1215,20 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase ensure TenantMembership.current_member = nil end + + def test_has_many_through_update_ids_with_conditions + author = Author.create :name => "Bill" + category = categories(:general) + author.update(special_categories_with_condition_ids: [category.id], + nonspecial_categories_with_condition_ids: [category.id]) + + assert_equal [category.id], author.special_categories_with_condition_ids + assert_equal [category.id], author.nonspecial_categories_with_condition_ids + + author.update(nonspecial_categories_with_condition_ids: []) + author.reload + + assert_equal [category.id], author.special_categories_with_condition_ids + assert_equal [], author.nonspecial_categories_with_condition_ids + end end diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 38b983eda0..4f1cf4ef81 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -85,6 +85,9 @@ class Author < ActiveRecord::Base has_many :special_categories, :through => :special_categorizations, :source => :category has_one :special_category, :through => :special_categorizations, :source => :category + has_many :special_categories_with_conditions, -> { where(categorizations: {special: true}) }, :through => :categorizations, :source => :category + has_many :nonspecial_categories_with_conditions, -> { where(categorizations: {special: false}) }, :through => :categorizations, :source => :category + has_many :categories_like_general, -> { where(:name => 'General') }, :through => :categorizations, :source => :category, :class_name => 'Category' has_many :categorized_posts, :through => :categorizations, :source => :post -- cgit v1.2.3