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.
- data/CHANGELOG +123 -30
- data/README.rdoc +2 -2
- data/lib/active_record/associations.rb +10 -9
- data/lib/active_record/associations/alias_tracker.rb +2 -2
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +19 -6
- data/lib/active_record/associations/collection_association.rb +61 -52
- data/lib/active_record/associations/collection_proxy.rb +30 -3
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -3
- data/lib/active_record/associations/join_helper.rb +1 -1
- data/lib/active_record/associations/singular_association.rb +13 -12
- data/lib/active_record/associations/through_association.rb +4 -1
- data/lib/active_record/base.rb +95 -46
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -9
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -3
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +28 -26
- data/lib/active_record/fixtures.rb +294 -339
- data/lib/active_record/identity_map.rb +34 -8
- data/lib/active_record/locking/optimistic.rb +16 -16
- data/lib/active_record/locking/pessimistic.rb +2 -2
- data/lib/active_record/observer.rb +3 -3
- data/lib/active_record/persistence.rb +1 -1
- data/lib/active_record/railties/controller_runtime.rb +10 -1
- data/lib/active_record/railties/databases.rake +9 -9
- data/lib/active_record/relation/calculations.rb +5 -6
- data/lib/active_record/relation/finder_methods.rb +9 -4
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/session_store.rb +4 -2
- data/lib/active_record/test_case.rb +7 -0
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/migration.rb +1 -1
- 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
|
-
*
|
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
|
-
|
536
|
-
|
537
|
-
|
628
|
+
class Book < ActiveRecord::Base
|
629
|
+
has_one :author
|
630
|
+
has_many :pages
|
538
631
|
|
539
|
-
|
540
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1587
|
-
|
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
|
-
|
2044
|
-
|
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
|
|
data/README.rdoc
CHANGED
@@ -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://
|
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.
|
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}.
|
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.
|
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
|
461
|
-
# Extensions can access relevant state using
|
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
|
-
# * +
|
464
|
-
# * +
|
465
|
-
# * +
|
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
|
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
|
-
|
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
|
@@ -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
|
-
#
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
341
|
-
|
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
|
-
|
351
|
-
|
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
|
-
|
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
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
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
|
-
|
407
|
-
|
408
|
-
|
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
|
-
|
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(
|
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)
|