activerecord 3.2.22.4 → 4.0.13
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2799 -617
- data/MIT-LICENSE +1 -1
- data/README.rdoc +23 -32
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +40 -34
- data/lib/active_record/association_relation.rb +22 -0
- data/lib/active_record/associations/alias_tracker.rb +4 -2
- data/lib/active_record/associations/association.rb +60 -46
- data/lib/active_record/associations/association_scope.rb +46 -40
- data/lib/active_record/associations/belongs_to_association.rb +17 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +81 -28
- data/lib/active_record/associations/builder/belongs_to.rb +73 -56
- data/lib/active_record/associations/builder/collection_association.rb +54 -40
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +13 -50
- data/lib/active_record/associations/builder/singular_association.rb +13 -13
- data/lib/active_record/associations/collection_association.rb +130 -96
- data/lib/active_record/associations/collection_proxy.rb +916 -63
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +15 -13
- data/lib/active_record/associations/has_many_association.rb +35 -8
- data/lib/active_record/associations/has_many_through_association.rb +37 -17
- data/lib/active_record/associations/has_one_association.rb +42 -19
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -22
- data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_part.rb +21 -8
- data/lib/active_record/associations/join_dependency.rb +30 -9
- data/lib/active_record/associations/join_helper.rb +1 -11
- data/lib/active_record/associations/preloader/association.rb +29 -33
- data/lib/active_record/associations/preloader/collection_association.rb +1 -1
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/through_association.rb +13 -17
- data/lib/active_record/associations/preloader.rb +20 -43
- data/lib/active_record/associations/singular_association.rb +11 -11
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +223 -282
- data/lib/active_record/attribute_assignment.rb +134 -154
- data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
- data/lib/active_record/attribute_methods/dirty.rb +36 -29
- data/lib/active_record/attribute_methods/primary_key.rb +45 -31
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +67 -90
- data/lib/active_record/attribute_methods/serialization.rb +133 -70
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +51 -45
- data/lib/active_record/attribute_methods/write.rb +34 -39
- data/lib/active_record/attribute_methods.rb +268 -108
- data/lib/active_record/autosave_association.rb +80 -73
- data/lib/active_record/base.rb +54 -451
- data/lib/active_record/callbacks.rb +60 -22
- data/lib/active_record/coders/yaml_column.rb +18 -21
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +347 -197
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +146 -138
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +19 -3
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +151 -142
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +499 -217
- data/lib/active_record/connection_adapters/abstract/transaction.rb +208 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +209 -44
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +169 -61
- data/lib/active_record/connection_adapters/column.rb +67 -36
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +28 -29
- data/lib/active_record/connection_adapters/mysql_adapter.rb +200 -73
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +98 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +160 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +240 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +374 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +183 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +508 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +544 -899
- data/lib/active_record/connection_adapters/schema_cache.rb +76 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +595 -16
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +472 -0
- data/lib/active_record/counter_cache.rb +107 -108
- data/lib/active_record/dynamic_matchers.rb +115 -63
- data/lib/active_record/errors.rb +36 -18
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +8 -4
- data/lib/active_record/fixture_set/file.rb +55 -0
- data/lib/active_record/fixtures.rb +159 -155
- data/lib/active_record/inheritance.rb +93 -59
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +39 -43
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +19 -9
- data/lib/active_record/migration/command_recorder.rb +102 -33
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +411 -173
- data/lib/active_record/model_schema.rb +81 -94
- data/lib/active_record/nested_attributes.rb +173 -131
- data/lib/active_record/null_relation.rb +67 -0
- data/lib/active_record/persistence.rb +254 -106
- data/lib/active_record/query_cache.rb +18 -36
- data/lib/active_record/querying.rb +19 -15
- data/lib/active_record/railtie.rb +113 -38
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +4 -3
- data/lib/active_record/railties/databases.rake +115 -368
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +7 -3
- data/lib/active_record/reflection.rb +110 -61
- data/lib/active_record/relation/batches.rb +29 -29
- data/lib/active_record/relation/calculations.rb +155 -125
- data/lib/active_record/relation/delegation.rb +94 -18
- data/lib/active_record/relation/finder_methods.rb +151 -203
- data/lib/active_record/relation/merger.rb +188 -0
- data/lib/active_record/relation/predicate_builder.rb +85 -42
- data/lib/active_record/relation/query_methods.rb +793 -146
- data/lib/active_record/relation/spawn_methods.rb +43 -150
- data/lib/active_record/relation.rb +293 -173
- data/lib/active_record/result.rb +48 -7
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/sanitization.rb +41 -54
- data/lib/active_record/schema.rb +19 -12
- data/lib/active_record/schema_dumper.rb +41 -41
- data/lib/active_record/schema_migration.rb +46 -0
- data/lib/active_record/scoping/default.rb +56 -52
- data/lib/active_record/scoping/named.rb +78 -103
- data/lib/active_record/scoping.rb +54 -124
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +9 -15
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/store.rb +131 -15
- data/lib/active_record/tasks/database_tasks.rb +204 -0
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +144 -0
- data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
- data/lib/active_record/test_case.rb +67 -38
- data/lib/active_record/timestamp.rb +16 -11
- data/lib/active_record/transactions.rb +73 -51
- data/lib/active_record/validations/associated.rb +19 -13
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +110 -57
- data/lib/active_record/validations.rb +18 -17
- data/lib/active_record/version.rb +7 -6
- data/lib/active_record.rb +63 -45
- data/lib/rails/generators/active_record/migration/migration_generator.rb +45 -8
- data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/model/model_generator.rb +5 -4
- data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -5
- metadata +43 -29
- data/examples/associations.png +0 -0
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -360
- data/lib/rails/generators/active_record/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext/array/wrap'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
# = Active Record Autosave Association
|
5
3
|
#
|
@@ -18,8 +16,9 @@ module ActiveRecord
|
|
18
16
|
# Note that it also means that associations marked for destruction won't
|
19
17
|
# be destroyed directly. They will however still be marked for destruction.
|
20
18
|
#
|
21
|
-
# Note that <tt
|
22
|
-
# When the <tt>:autosave</tt> option is not present new
|
19
|
+
# Note that <tt>autosave: false</tt> is not same as not declaring <tt>:autosave</tt>.
|
20
|
+
# When the <tt>:autosave</tt> option is not present then new association records are
|
21
|
+
# saved but the updated association records are not saved.
|
23
22
|
#
|
24
23
|
# == Validation
|
25
24
|
#
|
@@ -30,16 +29,14 @@ module ActiveRecord
|
|
30
29
|
# Association with autosave option defines several callbacks on your
|
31
30
|
# model (before_save, after_create, after_update). Please note that
|
32
31
|
# callbacks are executed in the order they were defined in
|
33
|
-
# model. You should avoid
|
32
|
+
# model. You should avoid modifying the association content, before
|
34
33
|
# autosave callbacks are executed. Placing your callbacks after
|
35
34
|
# associations is usually a good practice.
|
36
35
|
#
|
37
|
-
# == Examples
|
38
|
-
#
|
39
36
|
# === One-to-one Example
|
40
37
|
#
|
41
38
|
# class Post
|
42
|
-
# has_one :author, :
|
39
|
+
# has_one :author, autosave: true
|
43
40
|
# end
|
44
41
|
#
|
45
42
|
# Saving changes to the parent and its associated model can now be performed
|
@@ -66,43 +63,44 @@ module ActiveRecord
|
|
66
63
|
# Note that the model is _not_ yet removed from the database:
|
67
64
|
#
|
68
65
|
# id = post.author.id
|
69
|
-
# Author.
|
66
|
+
# Author.find_by(id: id).nil? # => false
|
70
67
|
#
|
71
68
|
# post.save
|
72
69
|
# post.reload.author # => nil
|
73
70
|
#
|
74
71
|
# Now it _is_ removed from the database:
|
75
72
|
#
|
76
|
-
# Author.
|
73
|
+
# Author.find_by(id: id).nil? # => true
|
77
74
|
#
|
78
75
|
# === One-to-many Example
|
79
76
|
#
|
80
77
|
# When <tt>:autosave</tt> is not declared new children are saved when their parent is saved:
|
81
78
|
#
|
82
79
|
# class Post
|
83
|
-
# has_many :comments # :autosave option is
|
80
|
+
# has_many :comments # :autosave option is not declared
|
84
81
|
# end
|
85
82
|
#
|
86
|
-
# post = Post.new(:
|
87
|
-
# post.comments.build(:
|
83
|
+
# post = Post.new(title: 'ruby rocks')
|
84
|
+
# post.comments.build(body: 'hello world')
|
88
85
|
# post.save # => saves both post and comment
|
89
86
|
#
|
90
|
-
# post = Post.create(:
|
91
|
-
# post.comments.build(:
|
87
|
+
# post = Post.create(title: 'ruby rocks')
|
88
|
+
# post.comments.build(body: 'hello world')
|
92
89
|
# post.save # => saves both post and comment
|
93
90
|
#
|
94
|
-
# post = Post.create(:
|
95
|
-
# post.comments.create(:
|
91
|
+
# post = Post.create(title: 'ruby rocks')
|
92
|
+
# post.comments.create(body: 'hello world')
|
96
93
|
# post.save # => saves both post and comment
|
97
94
|
#
|
98
|
-
# When <tt>:autosave</tt> is true all children
|
95
|
+
# When <tt>:autosave</tt> is true all children are saved, no matter whether they
|
96
|
+
# are new records or not:
|
99
97
|
#
|
100
98
|
# class Post
|
101
|
-
# has_many :comments, :
|
99
|
+
# has_many :comments, autosave: true
|
102
100
|
# end
|
103
101
|
#
|
104
|
-
# post = Post.create(:
|
105
|
-
# post.comments.create(:
|
102
|
+
# post = Post.create(title: 'ruby rocks')
|
103
|
+
# post.comments.create(body: 'hello world')
|
106
104
|
# post.comments[0].body = 'hi everyone'
|
107
105
|
# post.save # => saves both post and comment, with 'hi everyone' as body
|
108
106
|
#
|
@@ -116,35 +114,29 @@ module ActiveRecord
|
|
116
114
|
# Note that the model is _not_ yet removed from the database:
|
117
115
|
#
|
118
116
|
# id = post.comments.last.id
|
119
|
-
# Comment.
|
117
|
+
# Comment.find_by(id: id).nil? # => false
|
120
118
|
#
|
121
119
|
# post.save
|
122
120
|
# post.reload.comments.length # => 1
|
123
121
|
#
|
124
122
|
# Now it _is_ removed from the database:
|
125
123
|
#
|
126
|
-
# Comment.
|
124
|
+
# Comment.find_by(id: id).nil? # => true
|
127
125
|
|
128
126
|
module AutosaveAssociation
|
129
127
|
extend ActiveSupport::Concern
|
130
128
|
|
131
|
-
ASSOCIATION_TYPES = %w{ HasOne HasMany BelongsTo HasAndBelongsToMany }
|
132
|
-
|
133
129
|
module AssociationBuilderExtension #:nodoc:
|
134
|
-
def self.included(base)
|
135
|
-
base.valid_options << :autosave
|
136
|
-
end
|
137
|
-
|
138
130
|
def build
|
139
|
-
reflection = super
|
140
131
|
model.send(:add_autosave_association_callbacks, reflection)
|
141
|
-
|
132
|
+
super
|
142
133
|
end
|
143
134
|
end
|
144
135
|
|
145
136
|
included do
|
146
|
-
|
147
|
-
|
137
|
+
Associations::Builder::Association.class_eval do
|
138
|
+
self.valid_options << :autosave
|
139
|
+
include AssociationBuilderExtension
|
148
140
|
end
|
149
141
|
end
|
150
142
|
|
@@ -192,23 +184,21 @@ module ActiveRecord
|
|
192
184
|
# Doesn't use after_save as that would save associations added in after_create/after_update twice
|
193
185
|
after_create save_method
|
194
186
|
after_update save_method
|
187
|
+
elsif reflection.macro == :has_one
|
188
|
+
define_method(save_method) { save_has_one_association(reflection) }
|
189
|
+
# Configures two callbacks instead of a single after_save so that
|
190
|
+
# the model may rely on their execution order relative to its
|
191
|
+
# own callbacks.
|
192
|
+
#
|
193
|
+
# For example, given that after_creates run before after_saves, if
|
194
|
+
# we configured instead an after_save there would be no way to fire
|
195
|
+
# a custom after_create callback after the child association gets
|
196
|
+
# created.
|
197
|
+
after_create save_method
|
198
|
+
after_update save_method
|
195
199
|
else
|
196
|
-
|
197
|
-
|
198
|
-
# Configures two callbacks instead of a single after_save so that
|
199
|
-
# the model may rely on their execution order relative to its
|
200
|
-
# own callbacks.
|
201
|
-
#
|
202
|
-
# For example, given that after_creates run before after_saves, if
|
203
|
-
# we configured instead an after_save there would be no way to fire
|
204
|
-
# a custom after_create callback after the child association gets
|
205
|
-
# created.
|
206
|
-
after_create save_method
|
207
|
-
after_update save_method
|
208
|
-
else
|
209
|
-
define_non_cyclic_method(save_method, reflection) { save_belongs_to_association(reflection) }
|
210
|
-
before_save save_method
|
211
|
-
end
|
200
|
+
define_non_cyclic_method(save_method, reflection) { save_belongs_to_association(reflection) }
|
201
|
+
before_save save_method
|
212
202
|
end
|
213
203
|
end
|
214
204
|
|
@@ -223,6 +213,7 @@ module ActiveRecord
|
|
223
213
|
# Reloads the attributes of the object as usual and clears <tt>marked_for_destruction</tt> flag.
|
224
214
|
def reload(options = nil)
|
225
215
|
@marked_for_destruction = false
|
216
|
+
@destroyed_by_association = nil
|
226
217
|
super
|
227
218
|
end
|
228
219
|
|
@@ -242,6 +233,19 @@ module ActiveRecord
|
|
242
233
|
@marked_for_destruction
|
243
234
|
end
|
244
235
|
|
236
|
+
# Records the association that is being destroyed and destroying this
|
237
|
+
# record in the process.
|
238
|
+
def destroyed_by_association=(reflection)
|
239
|
+
@destroyed_by_association = reflection
|
240
|
+
end
|
241
|
+
|
242
|
+
# Returns the association for the parent being destroyed.
|
243
|
+
#
|
244
|
+
# Used to avoid updating the counter cache unnecessarily.
|
245
|
+
def destroyed_by_association
|
246
|
+
@destroyed_by_association
|
247
|
+
end
|
248
|
+
|
245
249
|
# Returns whether or not this record has been changed in any way (including whether
|
246
250
|
# any of its nested autosave associations are likewise changed)
|
247
251
|
def changed_for_autosave?
|
@@ -331,33 +335,29 @@ module ActiveRecord
|
|
331
335
|
autosave = reflection.options[:autosave]
|
332
336
|
|
333
337
|
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
|
334
|
-
begin
|
335
|
-
if autosave
|
336
|
-
records_to_destroy = records.select(&:marked_for_destruction?)
|
337
|
-
records_to_destroy.each { |record| association.proxy.destroy(record) }
|
338
|
-
records -= records_to_destroy
|
339
|
-
end
|
340
338
|
|
341
|
-
|
342
|
-
|
339
|
+
if autosave
|
340
|
+
records_to_destroy = records.select(&:marked_for_destruction?)
|
341
|
+
records_to_destroy.each { |record| association.destroy(record) }
|
342
|
+
records -= records_to_destroy
|
343
|
+
end
|
344
|
+
|
345
|
+
records.each do |record|
|
346
|
+
next if record.destroyed?
|
343
347
|
|
344
|
-
|
348
|
+
saved = true
|
345
349
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
end
|
352
|
-
elsif autosave
|
353
|
-
saved = record.save(:validate => false)
|
350
|
+
if autosave != false && (@new_record_before_save || record.new_record?)
|
351
|
+
if autosave
|
352
|
+
saved = association.insert_record(record, false)
|
353
|
+
else
|
354
|
+
association.insert_record(record) unless reflection.nested?
|
354
355
|
end
|
355
|
-
|
356
|
-
|
356
|
+
elsif autosave
|
357
|
+
saved = record.save(:validate => false)
|
357
358
|
end
|
358
|
-
|
359
|
-
|
360
|
-
raise
|
359
|
+
|
360
|
+
raise ActiveRecord::Rollback unless saved
|
361
361
|
end
|
362
362
|
end
|
363
363
|
|
@@ -382,9 +382,10 @@ module ActiveRecord
|
|
382
382
|
|
383
383
|
if autosave && record.marked_for_destruction?
|
384
384
|
record.destroy
|
385
|
-
|
385
|
+
elsif autosave != false
|
386
386
|
key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
|
387
|
-
|
387
|
+
|
388
|
+
if (autosave && record.changed_for_autosave?) || new_record? || record_changed?(reflection, record, key)
|
388
389
|
unless reflection.through_reflection
|
389
390
|
record[reflection.foreign_key] = key
|
390
391
|
end
|
@@ -397,6 +398,11 @@ module ActiveRecord
|
|
397
398
|
end
|
398
399
|
end
|
399
400
|
|
401
|
+
# If the record is new or it has changed, returns true.
|
402
|
+
def record_changed?(reflection, record, key)
|
403
|
+
record.new_record? || record[reflection.foreign_key] != key || record.changed_attributes.include?(reflection.foreign_key)
|
404
|
+
end
|
405
|
+
|
400
406
|
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
|
401
407
|
#
|
402
408
|
# In addition, it will destroy the association if it was marked for destruction.
|
@@ -407,6 +413,7 @@ module ActiveRecord
|
|
407
413
|
autosave = reflection.options[:autosave]
|
408
414
|
|
409
415
|
if autosave && record.marked_for_destruction?
|
416
|
+
self[reflection.foreign_key] = nil
|
410
417
|
record.destroy
|
411
418
|
elsif autosave != false
|
412
419
|
saved = record.save(:validate => !autosave) if record.new_record? || (autosave && record.changed_for_autosave?)
|