activerecord 3.1.0.beta1 → 3.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (35) hide show
  1. data/CHANGELOG +123 -30
  2. data/README.rdoc +2 -2
  3. data/lib/active_record/associations.rb +10 -9
  4. data/lib/active_record/associations/alias_tracker.rb +2 -2
  5. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  6. data/lib/active_record/associations/builder/singular_association.rb +19 -6
  7. data/lib/active_record/associations/collection_association.rb +61 -52
  8. data/lib/active_record/associations/collection_proxy.rb +30 -3
  9. data/lib/active_record/associations/has_one_association.rb +1 -1
  10. data/lib/active_record/associations/join_dependency/join_association.rb +3 -3
  11. data/lib/active_record/associations/join_helper.rb +1 -1
  12. data/lib/active_record/associations/singular_association.rb +13 -12
  13. data/lib/active_record/associations/through_association.rb +4 -1
  14. data/lib/active_record/base.rb +95 -46
  15. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -9
  16. data/lib/active_record/connection_adapters/column.rb +1 -1
  17. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -3
  18. data/lib/active_record/connection_adapters/postgresql_adapter.rb +28 -26
  19. data/lib/active_record/fixtures.rb +294 -339
  20. data/lib/active_record/identity_map.rb +34 -8
  21. data/lib/active_record/locking/optimistic.rb +16 -16
  22. data/lib/active_record/locking/pessimistic.rb +2 -2
  23. data/lib/active_record/observer.rb +3 -3
  24. data/lib/active_record/persistence.rb +1 -1
  25. data/lib/active_record/railties/controller_runtime.rb +10 -1
  26. data/lib/active_record/railties/databases.rake +9 -9
  27. data/lib/active_record/relation/calculations.rb +5 -6
  28. data/lib/active_record/relation/finder_methods.rb +9 -4
  29. data/lib/active_record/serialization.rb +1 -1
  30. data/lib/active_record/session_store.rb +4 -2
  31. data/lib/active_record/test_case.rb +7 -0
  32. data/lib/active_record/validations.rb +3 -3
  33. data/lib/active_record/version.rb +1 -1
  34. data/lib/rails/generators/active_record/model/templates/migration.rb +1 -1
  35. metadata +6 -6
data/CHANGELOG CHANGED
@@ -1,5 +1,36 @@
1
1
  *Rails 3.1.0 (unreleased)*
2
2
 
3
+ * Add block setting of attributes to singular associations:
4
+
5
+ class User < ActiveRecord::Base
6
+ has_one :account
7
+ end
8
+
9
+ user.build_account{ |a| a.credit_limit => 100.0 }
10
+
11
+ The block is called after the instance has been initialized. [Andrew White]
12
+
13
+ * Add ActiveRecord::Base.attribute_names to return a list of attribute names. This will return an empty array if the model is abstract or table does not exists. [Prem Sichanugrist]
14
+
15
+ * CSV Fixtures are deprecated and support will be removed in Rails 3.2.0
16
+
17
+ * AR#new, AR#create, AR#create!, AR#update_attributes and AR#update_attributes! all accept a second hash as option that allows you
18
+ to specify which role to consider when assigning attributes. This is built on top of ActiveModel's
19
+ new mass assignment capabilities:
20
+
21
+ class Post < ActiveRecord::Base
22
+ attr_accessible :title
23
+ attr_accessible :title, :published_at, :as => :admin
24
+ end
25
+
26
+ Post.new(params[:post], :as => :admin)
27
+
28
+ assign_attributes() with similar API was also added and attributes=(params, guard) was deprecated.
29
+
30
+ Please note that this changes the method signatures for AR#new, AR#create, AR#create!, AR#update_attributes and AR#update_attributes!. If you have overwritten these methods you should update them accordingly.
31
+
32
+ [Josh Kalderimis]
33
+
3
34
  * default_scope can take a block, lambda, or any other object which responds to `call` for lazy
4
35
  evaluation:
5
36
 
@@ -22,25 +53,7 @@
22
53
 
23
54
  [Jon Leighton]
24
55
 
25
- * Calling 'default_scope' multiple times in a class (including when a superclass calls
26
- 'default_scope') is deprecated. The current behavior is that this will merge the default
27
- scopes together:
28
-
29
- class Post < ActiveRecord::Base # Rails 3.1
30
- default_scope where(:published => true)
31
- default_scope where(:hidden => false)
32
- # The default scope is now: where(:published => true, :hidden => false)
33
- end
34
-
35
- In Rails 3.2, the behavior will be changed to overwrite previous scopes:
36
-
37
- class Post < ActiveRecord::Base # Rails 3.2
38
- default_scope where(:published => true)
39
- default_scope where(:hidden => false)
40
- # The default scope is now: where(:hidden => false)
41
- end
42
-
43
- If you wish to merge default scopes in special ways, it is recommended to define your default
56
+ * If you wish to merge default scopes in special ways, it is recommended to define your default
44
57
  scope as a class method and use the standard techniques for sharing code (inheritance, mixins,
45
58
  etc.):
46
59
 
@@ -293,6 +306,84 @@ IrreversibleMigration exception will be raised when going down.
293
306
  [Aaron Patterson]
294
307
 
295
308
 
309
+ *Rails 3.0.7 (April 18, 2011)*
310
+
311
+ * Destroying records via nested attributes works independent of reject_if LH #6006 [Durran Jordan]
312
+
313
+ * Delegate any? and many? to Model.scoped for consistency [Andrew White]
314
+
315
+ * Quote the ORDER BY clause in batched finds - fixes #6620 [Andrew White]
316
+
317
+ * Change exists? so records are not instantiated - fixes #6127. This prevents after_find
318
+ and after_initialize callbacks being triggered when checking for record existence.
319
+ [Andrew White]
320
+
321
+ * Fix performance bug with attribute accessors which only occurred on Ruby 1.8.7, and ensure we
322
+ cache type-casted values when the column returned from the db contains non-standard chars.
323
+ [Jon Leighton]
324
+
325
+ * Fix a performance regression introduced here 86acbf1cc050c8fa8c74a10c735e467fb6fd7df8
326
+ related to read_attribute method [Stian Grytøyr]
327
+
328
+
329
+ *Rails 3.0.6 (April 5, 2011)*
330
+
331
+ * Un-deprecate reorder method [Sebastian Martinez]
332
+
333
+ * Extensions are applied when calling +except+ or +only+ on relations.
334
+ Thanks to Iain Hecker.
335
+
336
+ * Schemas set in set_table_name are respected by the mysql adapter. LH #5322
337
+
338
+ * Fixed a bug when empty? was called on a grouped Relation that wasn't loaded.
339
+ LH #5829
340
+
341
+ * Reapply extensions when using except and only. Thanks Iain Hecker.
342
+
343
+ * Binary data is escaped when being inserted to SQLite3 Databases. Thanks
344
+ Naruse!
345
+
346
+
347
+ *Rails 3.0.5 (February 26, 2011)*
348
+
349
+ * Model.where(:column => 1).where(:column => 2) will always produce an AND
350
+ query.
351
+
352
+ [Aaron Patterson]
353
+
354
+ * Deprecated support for interpolated association conditions in the form of :conditions => 'foo = #{bar}'.
355
+
356
+ Instead, you should use a proc, like so:
357
+
358
+ Before:
359
+
360
+ has_many :things, :conditions => 'foo = #{bar}'
361
+
362
+ After:
363
+
364
+ has_many :things, :conditions => proc { "foo = #{bar}" }
365
+
366
+ Inside the proc, 'self' is the object which is the owner of the association, unless you are
367
+ eager loading the association, in which case 'self' is the class which the association is within.
368
+
369
+ You can have any "normal" conditions inside the proc, so the following will work too:
370
+
371
+ has_many :things, :conditions => proc { ["foo = ?", bar] }
372
+
373
+ Previously :insert_sql and :delete_sql on has_and_belongs_to_many association allowed you to call
374
+ 'record' to get the record being inserted or deleted. This is now passed as an argument to
375
+ the proc.
376
+
377
+ [Jon Leighton]
378
+
379
+
380
+ *Rails 3.0.4 (February 8, 2011)*
381
+
382
+ * Added deprecation warning for has_and_belongs_to_many associations where the join table has
383
+ additional attributes other than the keys. Access to these attributes is removed in 3.1.
384
+ Please use has_many :through instead. [Jon Leighton]
385
+
386
+
296
387
  *Rails 3.0.3 (November 16, 2010)*
297
388
 
298
389
  * Support find by class like this: Post.where(:name => Post)
@@ -329,10 +420,12 @@ IrreversibleMigration exception will be raised when going down.
329
420
 
330
421
  [Aaron Patterson]
331
422
 
423
+
332
424
  *Rails 3.0.1 (October 15, 2010)*
333
425
 
334
426
  * Introduce a fix for CVE-2010-3993
335
427
 
428
+
336
429
  *Rails 3.0.0 (August 29, 2010)*
337
430
 
338
431
  * Changed update_attribute to not run callbacks and update the record directly in the database [Neeraj Singh]
@@ -532,12 +625,12 @@ IrreversibleMigration exception will be raised when going down.
532
625
 
533
626
  * Add Support for updating deeply nested models from a single form. #1202 [Eloy Duran]
534
627
 
535
- class Book < ActiveRecord::Base
536
- has_one :author
537
- has_many :pages
628
+ class Book < ActiveRecord::Base
629
+ has_one :author
630
+ has_many :pages
538
631
 
539
- accepts_nested_attributes_for :author, :pages
540
- end
632
+ accepts_nested_attributes_for :author, :pages
633
+ end
541
634
 
542
635
  * Make after_save callbacks fire only if the record was successfully saved. #1735 [Michael Lovitt]
543
636
 
@@ -957,7 +1050,7 @@ so newlines etc are escaped #10385 [Norbert Crombach]
957
1050
  "foo.bar" => "`foo`.`bar`"
958
1051
 
959
1052
  * Complete the assimilation of Sexy Migrations from ErrFree [Chris Wanstrath, PJ Hyett]
960
- http://errtheblog.com/post/2381
1053
+ http://errtheblog.com/post/2381
961
1054
 
962
1055
  * Qualified column names work in hash conditions, like :conditions => { 'comments.created_at' => ... }. #9733 [Jack Danger Canty]
963
1056
 
@@ -1073,7 +1166,7 @@ single-table inheritance. #3833, #9886 [Gabriel Gironda, rramdas, François Bea
1073
1166
 
1074
1167
  * Improve performance and functionality of the postgresql adapter. Closes #8049 [roderickvd]
1075
1168
 
1076
- For more information see: http://dev.rubyonrails.org/ticket/8049
1169
+ For more information see: http://dev.rubyonrails.org/ticket/8049
1077
1170
 
1078
1171
  * Don't clobber includes passed to has_many.count [Jack Danger Canty]
1079
1172
 
@@ -1583,8 +1676,8 @@ during calendar reform. #7649, #7724 [fedot, Geoff Buesing]
1583
1676
  * Added support for conditions on Base.exists? #5689 [Josh Peek]. Examples:
1584
1677
 
1585
1678
  assert (Topic.exists?(:author_name => "David"))
1586
- assert (Topic.exists?(:author_name => "Mary", :approved => true))
1587
- assert (Topic.exists?(["parent_id = ?", 1]))
1679
+ assert (Topic.exists?(:author_name => "Mary", :approved => true))
1680
+ assert (Topic.exists?(["parent_id = ?", 1]))
1588
1681
 
1589
1682
  * Schema dumper quotes date :default values. [Dave Thomas]
1590
1683
 
@@ -2040,8 +2133,8 @@ during calendar reform. #7649, #7724 [fedot, Geoff Buesing]
2040
2133
  * Added support for conditions on Base.exists? #5689 [Josh Peek]. Examples:
2041
2134
 
2042
2135
  assert (Topic.exists?(:author_name => "David"))
2043
- assert (Topic.exists?(:author_name => "Mary", :approved => true))
2044
- assert (Topic.exists?(["parent_id = ?", 1]))
2136
+ assert (Topic.exists?(:author_name => "Mary", :approved => true))
2137
+ assert (Topic.exists?(["parent_id = ?", 1]))
2045
2138
 
2046
2139
  * Schema dumper quotes date :default values. [Dave Thomas]
2047
2140
 
@@ -84,7 +84,7 @@ A short rundown of some of the major features:
84
84
 
85
85
  class CommentObserver < ActiveRecord::Observer
86
86
  def after_create(comment) # is called just after Comment#save
87
- CommentMailer.new_comment_email("david@loudthinking.com", comment)
87
+ CommentMailer.new_comment_email("david@loudthinking.com", comment).deliver
88
88
  end
89
89
  end
90
90
 
@@ -219,4 +219,4 @@ API documentation is at
219
219
 
220
220
  Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
221
221
 
222
- * https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets
222
+ * https://github.com/rails/rails/issues
@@ -33,7 +33,7 @@ module ActiveRecord
33
33
 
34
34
  class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError #:nodoc:
35
35
  def initialize(owner_class_name, reflection, source_reflection)
36
- super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
36
+ super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
37
37
  end
38
38
  end
39
39
 
@@ -48,7 +48,7 @@ module ActiveRecord
48
48
  through_reflection = reflection.through_reflection
49
49
  source_reflection_names = reflection.source_reflection_names
50
50
  source_associations = reflection.through_reflection.klass.reflect_on_all_associations.collect { |a| a.name.inspect }
51
- super("Could not find the source association(s) #{source_reflection_names.collect{ |a| a.inspect }.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)}?")
51
+ super("Could not find the source association(s) #{source_reflection_names.collect{ |a| a.inspect }.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)}?")
52
52
  end
53
53
  end
54
54
 
@@ -96,7 +96,7 @@ module ActiveRecord
96
96
 
97
97
  class ReadOnlyAssociation < ActiveRecordError #:nodoc:
98
98
  def initialize(reflection)
99
- super("Can not add to a has_many :through association. Try adding to #{reflection.through_reflection.name.inspect}.")
99
+ super("Can not add to a has_many :through association. Try adding to #{reflection.through_reflection.name.inspect}.")
100
100
  end
101
101
  end
102
102
 
@@ -457,12 +457,13 @@ module ActiveRecord
457
457
  # has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
458
458
  # end
459
459
  #
460
- # Some extensions can only be made to work with knowledge of the association proxy's internals.
461
- # Extensions can access relevant state using accessors on the association proxy:
460
+ # Some extensions can only be made to work with knowledge of the association's internals.
461
+ # Extensions can access relevant state using the following methods (where 'items' is the
462
+ # name of the association):
462
463
  #
463
- # * +proxy_owner+ - Returns the object the association is part of.
464
- # * +proxy_reflection+ - Returns the reflection object that describes the association.
465
- # * +proxy_target+ - Returns the associated object for +belongs_to+ and +has_one+, or
464
+ # * +record.association(:items).owner+ - Returns the object the association is part of.
465
+ # * +record.association(:items).reflection+ - Returns the reflection object that describes the association.
466
+ # * +record.association(:items).target+ - Returns the associated object for +belongs_to+ and +has_one+, or
466
467
  # the collection of associated objects for +has_many+ and +has_and_belongs_to_many+.
467
468
  #
468
469
  # === Association Join Models
@@ -1379,7 +1380,7 @@ module ActiveRecord
1379
1380
  # [:touch]
1380
1381
  # If true, the associated object will be touched (the updated_at/on attributes set to now)
1381
1382
  # when this record is either saved or destroyed. If you specify a symbol, that attribute
1382
- # will be updated with the current time instead of the updated_at/on attribute.
1383
+ # will be updated with the current time in addition to the updated_at/on attribute.
1383
1384
  # [:inverse_of]
1384
1385
  # Specifies the name of the <tt>has_one</tt> or <tt>has_many</tt> association on the associated
1385
1386
  # object that is the inverse of this <tt>belongs_to</tt> association. Does not work in
@@ -49,8 +49,8 @@ module ActiveRecord
49
49
  end
50
50
  end
51
51
 
52
- def pluralize(table_name)
53
- ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name
52
+ def pluralize(table_name, base)
53
+ base.pluralize_table_names ? table_name.to_s.pluralize : table_name.to_s
54
54
  end
55
55
 
56
56
  private
@@ -19,7 +19,7 @@ module ActiveRecord
19
19
 
20
20
  def klass
21
21
  type = owner[reflection.foreign_type]
22
- type && type.constantize
22
+ type.presence && type.constantize
23
23
  end
24
24
 
25
25
  def raise_on_type_mismatch(record)
@@ -13,19 +13,32 @@ module ActiveRecord::Associations::Builder
13
13
 
14
14
  private
15
15
 
16
+ def define_readers
17
+ super
18
+ name = self.name
19
+
20
+ model.redefine_method("#{name}_loaded?") do
21
+ ActiveSupport::Deprecation.warn(
22
+ "Calling obj.#{name}_loaded? is deprecated. Please use " \
23
+ "obj.association(:#{name}).loaded? instead."
24
+ )
25
+ association(name).loaded?
26
+ end
27
+ end
28
+
16
29
  def define_constructors
17
30
  name = self.name
18
31
 
19
- model.redefine_method("build_#{name}") do |*params|
20
- association(name).build(*params)
32
+ model.redefine_method("build_#{name}") do |*params, &block|
33
+ association(name).build(*params, &block)
21
34
  end
22
35
 
23
- model.redefine_method("create_#{name}") do |*params|
24
- association(name).create(*params)
36
+ model.redefine_method("create_#{name}") do |*params, &block|
37
+ association(name).create(*params, &block)
25
38
  end
26
39
 
27
- model.redefine_method("create_#{name}!") do |*params|
28
- association(name).create!(*params)
40
+ model.redefine_method("create_#{name}!") do |*params, &block|
41
+ association(name).create!(*params, &block)
29
42
  end
30
43
  end
31
44
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module Associations
5
5
  # = Active Record Association Collection
6
6
  #
7
- # AssociationCollection is an abstract class that provides common stuff to
7
+ # CollectionAssociation is an abstract class that provides common stuff to
8
8
  # ease the implementation of association proxies that represent
9
9
  # collections. See the class hierarchy in AssociationProxy.
10
10
  #
@@ -94,7 +94,13 @@ module ActiveRecord
94
94
  end
95
95
 
96
96
  def build(attributes = {}, options = {}, &block)
97
- build_or_create(:build, attributes, options, &block)
97
+ if attributes.is_a?(Array)
98
+ attributes.collect { |attr| build(attr, options, &block) }
99
+ else
100
+ add_to_target(build_record(attributes, options)) do |record|
101
+ yield(record) if block_given?
102
+ end
103
+ end
98
104
  end
99
105
 
100
106
  def create(attributes = {}, options = {}, &block)
@@ -102,7 +108,16 @@ module ActiveRecord
102
108
  raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
103
109
  end
104
110
 
105
- build_or_create(:create, attributes, options, &block)
111
+ if attributes.is_a?(Array)
112
+ attributes.collect { |attr| create(attr, options, &block) }
113
+ else
114
+ transaction do
115
+ add_to_target(build_record(attributes, options)) do |record|
116
+ yield(record) if block_given?
117
+ insert_record(record)
118
+ end
119
+ end
120
+ end
106
121
  end
107
122
 
108
123
  def create!(attrs = {}, options = {}, &block)
@@ -321,15 +336,7 @@ module ActiveRecord
321
336
 
322
337
  def load_target
323
338
  if find_target?
324
- targets = []
325
-
326
- begin
327
- targets = find_target
328
- rescue ActiveRecord::RecordNotFound
329
- reset
330
- end
331
-
332
- @target = merge_target_lists(targets, target)
339
+ @target = merge_target_lists(find_target, target)
333
340
  end
334
341
 
335
342
  loaded!
@@ -337,20 +344,18 @@ module ActiveRecord
337
344
  end
338
345
 
339
346
  def add_to_target(record)
340
- transaction do
341
- callback(:before_add, record)
342
- yield(record) if block_given?
343
-
344
- if options[:uniq] && index = @target.index(record)
345
- @target[index] = record
346
- else
347
- @target << record
348
- end
347
+ callback(:before_add, record)
348
+ yield(record) if block_given?
349
349
 
350
- callback(:after_add, record)
351
- set_inverse_instance(record)
350
+ if options[:uniq] && index = @target.index(record)
351
+ @target[index] = record
352
+ else
353
+ @target << record
352
354
  end
353
355
 
356
+ callback(:after_add, record)
357
+ set_inverse_instance(record)
358
+
354
359
  record
355
360
  end
356
361
 
@@ -374,7 +379,7 @@ module ActiveRecord
374
379
  if options[:finder_sql]
375
380
  reflection.klass.find_by_sql(custom_finder_sql)
376
381
  else
377
- find(:all)
382
+ scoped.all
378
383
  end
379
384
 
380
385
  records = options[:uniq] ? uniq(records) : records
@@ -382,38 +387,35 @@ module ActiveRecord
382
387
  records
383
388
  end
384
389
 
385
- def merge_target_lists(loaded, existing)
386
- return loaded if existing.empty?
387
- return existing if loaded.empty?
388
-
389
- loaded.map do |f|
390
- i = existing.index(f)
391
- if i
392
- existing.delete_at(i).tap do |t|
393
- keys = ["id"] + t.changes.keys + (f.attribute_names - t.attribute_names)
394
- # FIXME: this call to attributes causes many NoMethodErrors
395
- attributes = f.attributes
396
- (attributes.keys - keys).each do |k|
397
- t.send("#{k}=", attributes[k])
398
- end
390
+ # We have some records loaded from the database (persisted) and some that are
391
+ # in-memory (memory). The same record may be represented in the persisted array
392
+ # and in the memory array.
393
+ #
394
+ # So the task of this method is to merge them according to the following rules:
395
+ #
396
+ # * The final array must not have duplicates
397
+ # * The order of the persisted array is to be preserved
398
+ # * Any changes made to attributes on objects in the memory array are to be preserved
399
+ # * Otherwise, attributes should have the value found in the database
400
+ def merge_target_lists(persisted, memory)
401
+ return persisted if memory.empty?
402
+ return memory if persisted.empty?
403
+
404
+ persisted.map! do |record|
405
+ mem_record = memory.delete(record)
406
+
407
+ if mem_record
408
+ (record.attribute_names - mem_record.changes.keys).each do |name|
409
+ mem_record[name] = record[name]
399
410
  end
400
- else
401
- f
402
- end
403
- end + existing
404
- end
405
411
 
406
- def build_or_create(method, attributes, options)
407
- records = Array.wrap(attributes).map do |attrs|
408
- record = build_record(attrs, options)
409
-
410
- add_to_target(record) do
411
- yield(record) if block_given?
412
- insert_record(record) if method == :create
412
+ mem_record
413
+ else
414
+ record
413
415
  end
414
416
  end
415
417
 
416
- attributes.is_a?(Array) ? records : records.first
418
+ persisted + memory
417
419
  end
418
420
 
419
421
  # Do the relevant stuff to insert the given record into the association collection.
@@ -421,8 +423,15 @@ module ActiveRecord
421
423
  raise NotImplementedError
422
424
  end
423
425
 
426
+ def create_scope
427
+ scoped.scope_for_create.stringify_keys
428
+ end
429
+
424
430
  def build_record(attributes, options)
425
- reflection.build_association(scoped.scope_for_create.merge(attributes), options)
431
+ record = reflection.build_association(attributes, options)
432
+ record.assign_attributes(create_scope.except(*record.changed), :without_protection => true)
433
+ record.assign_attributes(attributes, options)
434
+ record
426
435
  end
427
436
 
428
437
  def delete_or_destroy(records, method)