diff options
author | Darwin D Wu <wuddarwin@gmail.com> | 2018-08-15 17:18:51 -0700 |
---|---|---|
committer | Darwin D Wu <wuddarwin@gmail.com> | 2018-09-11 00:13:09 -0700 |
commit | 5291044a1d7866d2942276d812a5d3a72a67ef27 (patch) | |
tree | 3bb6f91fdec76505a2ff1104adda74dd6773dd99 /activerecord/lib | |
parent | 5b0b1ee8fda1cd086653992f812f96c62fb3c24b (diff) | |
download | rails-5291044a1d7866d2942276d812a5d3a72a67ef27.tar.gz rails-5291044a1d7866d2942276d812a5d3a72a67ef27.tar.bz2 rails-5291044a1d7866d2942276d812a5d3a72a67ef27.zip |
Fixes #33610
In order to avoid double assignments of nested_attributes for `has_many`
relations during record initialization, nested_attributes in `create_with`
should not be passed into `klass.new` and have them populate during
`initialize_internals_callback` with scope attributes.
However, `create_with` keys should always have precedence over where
clauses, so if there are same keys in both `create_with` and
`where_values_hash`, the value in `create_with` should be the one that's
used.
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/relation.rb | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 29a3ceab7d..c4e48cdb67 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -62,7 +62,7 @@ module ActiveRecord # user = users.new { |user| user.name = 'Oscar' } # user.name # => Oscar def new(attributes = nil, &block) - scoping { klass.new(scope_for_create(attributes), &block) } + scoping { klass.new(values_for_create(attributes), &block) } end alias build new @@ -90,7 +90,7 @@ module ActiveRecord if attributes.is_a?(Array) attributes.collect { |attr| create(attr, &block) } else - scoping { klass.create(scope_for_create(attributes), &block) } + scoping { klass.create(values_for_create(attributes), &block) } end end @@ -104,7 +104,7 @@ module ActiveRecord if attributes.is_a?(Array) attributes.collect { |attr| create!(attr, &block) } else - scoping { klass.create!(scope_for_create(attributes), &block) } + scoping { klass.create!(values_for_create(attributes), &block) } end end @@ -554,10 +554,8 @@ module ActiveRecord where_clause.to_h(relation_table_name) end - def scope_for_create(attributes = nil) - scope = where_values_hash.merge!(create_with_value.stringify_keys) - scope.merge!(attributes) if attributes - scope + def scope_for_create + where_values_hash.merge!(create_with_value.stringify_keys) end # Returns true if relation needs eager loading. @@ -708,5 +706,18 @@ module ActiveRecord # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"] end + + def values_for_create(attributes = nil) + result = attributes ? where_values_hash.merge!(attributes) : where_values_hash + + # NOTE: if there are same keys in both create_with and result, create_with should be used. + # This is to make sure nested attributes don't get passed to the klass.new, + # while keeping the precedence of the duplicate keys in create_with. + create_with_value.stringify_keys.each do |k, v| + result[k] = v if result.key?(k) + end + + result + end end end |