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.

Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2799 -617
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +23 -32
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +40 -34
  7. data/lib/active_record/association_relation.rb +22 -0
  8. data/lib/active_record/associations/alias_tracker.rb +4 -2
  9. data/lib/active_record/associations/association.rb +60 -46
  10. data/lib/active_record/associations/association_scope.rb +46 -40
  11. data/lib/active_record/associations/belongs_to_association.rb +17 -4
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  13. data/lib/active_record/associations/builder/association.rb +81 -28
  14. data/lib/active_record/associations/builder/belongs_to.rb +73 -56
  15. data/lib/active_record/associations/builder/collection_association.rb +54 -40
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -64
  18. data/lib/active_record/associations/builder/has_one.rb +13 -50
  19. data/lib/active_record/associations/builder/singular_association.rb +13 -13
  20. data/lib/active_record/associations/collection_association.rb +130 -96
  21. data/lib/active_record/associations/collection_proxy.rb +916 -63
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +15 -13
  23. data/lib/active_record/associations/has_many_association.rb +35 -8
  24. data/lib/active_record/associations/has_many_through_association.rb +37 -17
  25. data/lib/active_record/associations/has_one_association.rb +42 -19
  26. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_association.rb +39 -22
  28. data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
  29. data/lib/active_record/associations/join_dependency/join_part.rb +21 -8
  30. data/lib/active_record/associations/join_dependency.rb +30 -9
  31. data/lib/active_record/associations/join_helper.rb +1 -11
  32. data/lib/active_record/associations/preloader/association.rb +29 -33
  33. data/lib/active_record/associations/preloader/collection_association.rb +1 -1
  34. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
  36. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +13 -17
  38. data/lib/active_record/associations/preloader.rb +20 -43
  39. data/lib/active_record/associations/singular_association.rb +11 -11
  40. data/lib/active_record/associations/through_association.rb +3 -3
  41. data/lib/active_record/associations.rb +223 -282
  42. data/lib/active_record/attribute_assignment.rb +134 -154
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
  44. data/lib/active_record/attribute_methods/dirty.rb +36 -29
  45. data/lib/active_record/attribute_methods/primary_key.rb +45 -31
  46. data/lib/active_record/attribute_methods/query.rb +5 -4
  47. data/lib/active_record/attribute_methods/read.rb +67 -90
  48. data/lib/active_record/attribute_methods/serialization.rb +133 -70
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +51 -45
  50. data/lib/active_record/attribute_methods/write.rb +34 -39
  51. data/lib/active_record/attribute_methods.rb +268 -108
  52. data/lib/active_record/autosave_association.rb +80 -73
  53. data/lib/active_record/base.rb +54 -451
  54. data/lib/active_record/callbacks.rb +60 -22
  55. data/lib/active_record/coders/yaml_column.rb +18 -21
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +347 -197
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +146 -138
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -19
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +19 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +151 -142
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +499 -217
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +208 -0
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +209 -44
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +169 -61
  67. data/lib/active_record/connection_adapters/column.rb +67 -36
  68. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +28 -29
  70. data/lib/active_record/connection_adapters/mysql_adapter.rb +200 -73
  71. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +98 -0
  72. data/lib/active_record/connection_adapters/postgresql/cast.rb +160 -0
  73. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +240 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +374 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +183 -0
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +508 -0
  78. data/lib/active_record/connection_adapters/postgresql_adapter.rb +544 -899
  79. data/lib/active_record/connection_adapters/schema_cache.rb +76 -16
  80. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +595 -16
  81. data/lib/active_record/connection_handling.rb +98 -0
  82. data/lib/active_record/core.rb +472 -0
  83. data/lib/active_record/counter_cache.rb +107 -108
  84. data/lib/active_record/dynamic_matchers.rb +115 -63
  85. data/lib/active_record/errors.rb +36 -18
  86. data/lib/active_record/explain.rb +15 -63
  87. data/lib/active_record/explain_registry.rb +30 -0
  88. data/lib/active_record/explain_subscriber.rb +8 -4
  89. data/lib/active_record/fixture_set/file.rb +55 -0
  90. data/lib/active_record/fixtures.rb +159 -155
  91. data/lib/active_record/inheritance.rb +93 -59
  92. data/lib/active_record/integration.rb +8 -8
  93. data/lib/active_record/locale/en.yml +8 -1
  94. data/lib/active_record/locking/optimistic.rb +39 -43
  95. data/lib/active_record/locking/pessimistic.rb +4 -4
  96. data/lib/active_record/log_subscriber.rb +19 -9
  97. data/lib/active_record/migration/command_recorder.rb +102 -33
  98. data/lib/active_record/migration/join_table.rb +15 -0
  99. data/lib/active_record/migration.rb +411 -173
  100. data/lib/active_record/model_schema.rb +81 -94
  101. data/lib/active_record/nested_attributes.rb +173 -131
  102. data/lib/active_record/null_relation.rb +67 -0
  103. data/lib/active_record/persistence.rb +254 -106
  104. data/lib/active_record/query_cache.rb +18 -36
  105. data/lib/active_record/querying.rb +19 -15
  106. data/lib/active_record/railtie.rb +113 -38
  107. data/lib/active_record/railties/console_sandbox.rb +3 -4
  108. data/lib/active_record/railties/controller_runtime.rb +4 -3
  109. data/lib/active_record/railties/databases.rake +115 -368
  110. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  111. data/lib/active_record/readonly_attributes.rb +7 -3
  112. data/lib/active_record/reflection.rb +110 -61
  113. data/lib/active_record/relation/batches.rb +29 -29
  114. data/lib/active_record/relation/calculations.rb +155 -125
  115. data/lib/active_record/relation/delegation.rb +94 -18
  116. data/lib/active_record/relation/finder_methods.rb +151 -203
  117. data/lib/active_record/relation/merger.rb +188 -0
  118. data/lib/active_record/relation/predicate_builder.rb +85 -42
  119. data/lib/active_record/relation/query_methods.rb +793 -146
  120. data/lib/active_record/relation/spawn_methods.rb +43 -150
  121. data/lib/active_record/relation.rb +293 -173
  122. data/lib/active_record/result.rb +48 -7
  123. data/lib/active_record/runtime_registry.rb +17 -0
  124. data/lib/active_record/sanitization.rb +41 -54
  125. data/lib/active_record/schema.rb +19 -12
  126. data/lib/active_record/schema_dumper.rb +41 -41
  127. data/lib/active_record/schema_migration.rb +46 -0
  128. data/lib/active_record/scoping/default.rb +56 -52
  129. data/lib/active_record/scoping/named.rb +78 -103
  130. data/lib/active_record/scoping.rb +54 -124
  131. data/lib/active_record/serialization.rb +6 -2
  132. data/lib/active_record/serializers/xml_serializer.rb +9 -15
  133. data/lib/active_record/statement_cache.rb +26 -0
  134. data/lib/active_record/store.rb +131 -15
  135. data/lib/active_record/tasks/database_tasks.rb +204 -0
  136. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  137. data/lib/active_record/tasks/mysql_database_tasks.rb +144 -0
  138. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  139. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  140. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  141. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  142. data/lib/active_record/test_case.rb +67 -38
  143. data/lib/active_record/timestamp.rb +16 -11
  144. data/lib/active_record/transactions.rb +73 -51
  145. data/lib/active_record/validations/associated.rb +19 -13
  146. data/lib/active_record/validations/presence.rb +65 -0
  147. data/lib/active_record/validations/uniqueness.rb +110 -57
  148. data/lib/active_record/validations.rb +18 -17
  149. data/lib/active_record/version.rb +7 -6
  150. data/lib/active_record.rb +63 -45
  151. data/lib/rails/generators/active_record/migration/migration_generator.rb +45 -8
  152. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
  153. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  154. data/lib/rails/generators/active_record/model/model_generator.rb +5 -4
  155. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  156. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  157. data/lib/rails/generators/active_record.rb +3 -5
  158. metadata +43 -29
  159. data/examples/associations.png +0 -0
  160. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  161. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  162. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  163. data/lib/active_record/dynamic_finder_match.rb +0 -68
  164. data/lib/active_record/dynamic_scope_match.rb +0 -23
  165. data/lib/active_record/fixtures/file.rb +0 -65
  166. data/lib/active_record/identity_map.rb +0 -162
  167. data/lib/active_record/observer.rb +0 -121
  168. data/lib/active_record/session_store.rb +0 -360
  169. data/lib/rails/generators/active_record/migration.rb +0 -15
  170. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  171. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  172. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  173. 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>:autosave => false</tt> is not same as not declaring <tt>:autosave</tt>.
22
- # When the <tt>:autosave</tt> option is not present new associations are saved.
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 modyfing the association content, before
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, :autosave => true
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.find_by_id(id).nil? # => false
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.find_by_id(id).nil? # => true
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 no declared
80
+ # has_many :comments # :autosave option is not declared
84
81
  # end
85
82
  #
86
- # post = Post.new(:title => 'ruby rocks')
87
- # post.comments.build(:body => 'hello world')
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(:title => 'ruby rocks')
91
- # post.comments.build(:body => 'hello world')
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(:title => 'ruby rocks')
95
- # post.comments.create(:body => 'hello world')
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 is saved, no matter whether they are new records:
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, :autosave => true
99
+ # has_many :comments, autosave: true
102
100
  # end
103
101
  #
104
- # post = Post.create(:title => 'ruby rocks')
105
- # post.comments.create(:body => 'hello world')
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.find_by_id(id).nil? # => false
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.find_by_id(id).nil? # => true
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
- reflection
132
+ super
142
133
  end
143
134
  end
144
135
 
145
136
  included do
146
- ASSOCIATION_TYPES.each do |type|
147
- Associations::Builder.const_get(type).send(:include, AssociationBuilderExtension)
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
- if reflection.macro == :has_one
197
- define_method(save_method) { save_has_one_association(reflection) }
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
- records.each do |record|
342
- next if record.destroyed?
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
- saved = true
348
+ saved = true
345
349
 
346
- if autosave != false && (@new_record_before_save || record.new_record?)
347
- if autosave
348
- saved = association.insert_record(record, false)
349
- else
350
- association.insert_record(record) unless reflection.nested?
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
- raise ActiveRecord::Rollback unless saved
356
+ elsif autosave
357
+ saved = record.save(:validate => false)
357
358
  end
358
- rescue
359
- records.each {|x| IdentityMap.remove(x) } if IdentityMap.enabled?
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
- else
385
+ elsif autosave != false
386
386
  key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
387
- if autosave != false && (new_record? || record.new_record? || record[reflection.foreign_key] != key || autosave)
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?)