From 4189c65316f606508709d7157fcb4113d32d1c6a Mon Sep 17 00:00:00 2001 From: Guilherme Goettems Schneider Date: Wed, 4 May 2016 15:36:07 -0300 Subject: [PATCH] Fix `ActiveRecord::Relation#create` and `#create!` scope leaking to callbacks Fixes #7391, #7853, #9894, #12305, #18952. --- activerecord/CHANGELOG.md | 7 +++++++ activerecord/lib/active_record/relation.rb | 16 ++++++++++++---- activerecord/test/cases/relations_test.rb | 18 ++++++++++++++++++ activerecord/test/models/bird.rb | 7 +++++++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index fdf310f15fbb2..1b01a37ab735d 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,10 @@ +* Fix `ActiveRecord::Relation#create` and `#create!` scope leaking to + callbacks + + Fixes #7391, #7853, #9894, #12305, #18952. + + *Guilherme Goettems Schneider* + ## Rails 5.0.0.beta4 (April 27, 2016) ## * PostgreSQL: Support Expression Indexes and Operator Classes. diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index d042fe5f8b401..0d720f810c7df 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -146,8 +146,12 @@ def new(*args, &block) # # users.create(name: nil) # validation on name # # => # - def create(*args, &block) - scoping { @klass.create(*args, &block) } + def create(args = nil, &block) + if args.is_a?(Array) + args.map { |attr| create(attr, &block) } + else + new(args, &block).tap(&:save) + end end # Similar to #create, but calls @@ -156,8 +160,12 @@ def create(*args, &block) # # Expects arguments in the same format as # {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!]. - def create!(*args, &block) - scoping { @klass.create!(*args, &block) } + def create!(args = nil, &block) + if args.is_a?(Array) + args.map { |attr| create!(attr, &block) } + else + new(args, &block).tap(&:save!) + end end def first_or_create(attributes = nil, &block) # :nodoc: diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 95e4230a5884a..884cdf8ff2e64 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1327,6 +1327,24 @@ def test_create_bang assert_equal 'hen', hen.name end + def test_create_with_callback + parrot = Bird.create!(name: 'parrot', color: 'green') + + birds = Bird.all + hen = birds.where(name: 'hen').create do |bird| + bird.evangelist = true + bird.color = 'blue' + end + + assert_kind_of Bird, hen + assert hen.persisted? + assert_equal 'hen', hen.name + assert_equal 'blue', hen.color + + parrot.reload + assert_equal 'blue', parrot.color + end + def test_first_or_create parrot = Bird.where(:color => 'green').first_or_create(:name => 'parrot') assert_kind_of Bird, parrot diff --git a/activerecord/test/models/bird.rb b/activerecord/test/models/bird.rb index 2a51d903b81c6..094cb50e18c1d 100644 --- a/activerecord/test/models/bird.rb +++ b/activerecord/test/models/bird.rb @@ -9,4 +9,11 @@ class Bird < ActiveRecord::Base def cancel_save_callback_method throw(:abort) end + + attr_accessor :evangelist + after_save :convert_all_to_my_color, if: :evangelist + def convert_all_to_my_color + self.class.update_all(color: color) + end + end