activerecord 4.2.11.3 → 5.0.7.2

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 (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1638 -1132
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +7 -2
  8. data/lib/active_record/aggregations.rb +34 -21
  9. data/lib/active_record/association_relation.rb +7 -4
  10. data/lib/active_record/associations.rb +347 -218
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +22 -10
  13. data/lib/active_record/associations/association_scope.rb +75 -104
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +13 -11
  22. data/lib/active_record/associations/collection_association.rb +85 -69
  23. data/lib/active_record/associations/collection_proxy.rb +104 -46
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +21 -78
  26. data/lib/active_record/associations/has_many_through_association.rb +6 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +38 -22
  29. data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +14 -4
  32. data/lib/active_record/associations/preloader/association.rb +52 -71
  33. data/lib/active_record/associations/preloader/collection_association.rb +0 -7
  34. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +36 -17
  38. data/lib/active_record/associations/singular_association.rb +13 -1
  39. data/lib/active_record/associations/through_association.rb +12 -4
  40. data/lib/active_record/attribute.rb +69 -19
  41. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  42. data/lib/active_record/attribute_assignment.rb +19 -140
  43. data/lib/active_record/attribute_decorators.rb +6 -5
  44. data/lib/active_record/attribute_methods.rb +69 -44
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  46. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  47. data/lib/active_record/attribute_methods/primary_key.rb +16 -3
  48. data/lib/active_record/attribute_methods/query.rb +2 -2
  49. data/lib/active_record/attribute_methods/read.rb +31 -59
  50. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  52. data/lib/active_record/attribute_methods/write.rb +13 -37
  53. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  54. data/lib/active_record/attribute_set.rb +32 -3
  55. data/lib/active_record/attribute_set/builder.rb +42 -16
  56. data/lib/active_record/attributes.rb +199 -81
  57. data/lib/active_record/autosave_association.rb +54 -17
  58. data/lib/active_record/base.rb +32 -23
  59. data/lib/active_record/callbacks.rb +39 -43
  60. data/lib/active_record/coders/json.rb +1 -1
  61. data/lib/active_record/coders/yaml_column.rb +20 -8
  62. data/lib/active_record/collection_cache_key.rb +50 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
  76. data/lib/active_record/connection_adapters/column.rb +28 -43
  77. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  78. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  79. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  80. data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
  81. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  82. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  87. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
  88. data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
  89. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
  90. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
  93. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  99. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  102. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
  116. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  121. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
  122. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  123. data/lib/active_record/connection_handling.rb +37 -14
  124. data/lib/active_record/core.rb +92 -108
  125. data/lib/active_record/counter_cache.rb +13 -24
  126. data/lib/active_record/dynamic_matchers.rb +1 -20
  127. data/lib/active_record/enum.rb +116 -76
  128. data/lib/active_record/errors.rb +87 -48
  129. data/lib/active_record/explain.rb +20 -9
  130. data/lib/active_record/explain_registry.rb +1 -1
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +26 -5
  133. data/lib/active_record/fixtures.rb +77 -41
  134. data/lib/active_record/gem_version.rb +4 -4
  135. data/lib/active_record/inheritance.rb +32 -40
  136. data/lib/active_record/integration.rb +17 -14
  137. data/lib/active_record/internal_metadata.rb +56 -0
  138. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  139. data/lib/active_record/locale/en.yml +3 -2
  140. data/lib/active_record/locking/optimistic.rb +15 -15
  141. data/lib/active_record/locking/pessimistic.rb +1 -1
  142. data/lib/active_record/log_subscriber.rb +48 -24
  143. data/lib/active_record/migration.rb +362 -111
  144. data/lib/active_record/migration/command_recorder.rb +59 -18
  145. data/lib/active_record/migration/compatibility.rb +126 -0
  146. data/lib/active_record/model_schema.rb +270 -73
  147. data/lib/active_record/nested_attributes.rb +58 -29
  148. data/lib/active_record/no_touching.rb +4 -0
  149. data/lib/active_record/null_relation.rb +16 -8
  150. data/lib/active_record/persistence.rb +152 -90
  151. data/lib/active_record/query_cache.rb +18 -23
  152. data/lib/active_record/querying.rb +12 -11
  153. data/lib/active_record/railtie.rb +23 -16
  154. data/lib/active_record/railties/controller_runtime.rb +1 -1
  155. data/lib/active_record/railties/databases.rake +52 -41
  156. data/lib/active_record/readonly_attributes.rb +1 -1
  157. data/lib/active_record/reflection.rb +302 -115
  158. data/lib/active_record/relation.rb +187 -120
  159. data/lib/active_record/relation/batches.rb +141 -36
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  161. data/lib/active_record/relation/calculations.rb +92 -117
  162. data/lib/active_record/relation/delegation.rb +8 -20
  163. data/lib/active_record/relation/finder_methods.rb +173 -89
  164. data/lib/active_record/relation/from_clause.rb +32 -0
  165. data/lib/active_record/relation/merger.rb +16 -42
  166. data/lib/active_record/relation/predicate_builder.rb +120 -107
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  168. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  169. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  170. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  171. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  173. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  175. data/lib/active_record/relation/query_attribute.rb +19 -0
  176. data/lib/active_record/relation/query_methods.rb +308 -244
  177. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  178. data/lib/active_record/relation/spawn_methods.rb +4 -7
  179. data/lib/active_record/relation/where_clause.rb +174 -0
  180. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  181. data/lib/active_record/result.rb +11 -4
  182. data/lib/active_record/runtime_registry.rb +1 -1
  183. data/lib/active_record/sanitization.rb +105 -66
  184. data/lib/active_record/schema.rb +26 -22
  185. data/lib/active_record/schema_dumper.rb +54 -37
  186. data/lib/active_record/schema_migration.rb +11 -14
  187. data/lib/active_record/scoping.rb +34 -16
  188. data/lib/active_record/scoping/default.rb +28 -10
  189. data/lib/active_record/scoping/named.rb +59 -26
  190. data/lib/active_record/secure_token.rb +38 -0
  191. data/lib/active_record/serialization.rb +3 -5
  192. data/lib/active_record/statement_cache.rb +17 -15
  193. data/lib/active_record/store.rb +8 -3
  194. data/lib/active_record/suppressor.rb +58 -0
  195. data/lib/active_record/table_metadata.rb +69 -0
  196. data/lib/active_record/tasks/database_tasks.rb +66 -49
  197. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  198. data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
  199. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  200. data/lib/active_record/timestamp.rb +20 -9
  201. data/lib/active_record/touch_later.rb +63 -0
  202. data/lib/active_record/transactions.rb +139 -57
  203. data/lib/active_record/type.rb +66 -17
  204. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  205. data/lib/active_record/type/date.rb +2 -45
  206. data/lib/active_record/type/date_time.rb +2 -49
  207. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  208. data/lib/active_record/type/internal/timezone.rb +15 -0
  209. data/lib/active_record/type/serialized.rb +15 -14
  210. data/lib/active_record/type/time.rb +10 -16
  211. data/lib/active_record/type/type_map.rb +4 -4
  212. data/lib/active_record/type_caster.rb +7 -0
  213. data/lib/active_record/type_caster/connection.rb +29 -0
  214. data/lib/active_record/type_caster/map.rb +19 -0
  215. data/lib/active_record/validations.rb +33 -32
  216. data/lib/active_record/validations/absence.rb +23 -0
  217. data/lib/active_record/validations/associated.rb +10 -3
  218. data/lib/active_record/validations/length.rb +24 -0
  219. data/lib/active_record/validations/presence.rb +11 -12
  220. data/lib/active_record/validations/uniqueness.rb +33 -33
  221. data/lib/rails/generators/active_record/migration.rb +15 -0
  222. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
  223. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  224. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
  226. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  227. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  228. metadata +58 -34
  229. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  230. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  231. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  232. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  233. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  234. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  235. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  236. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  237. data/lib/active_record/type/big_integer.rb +0 -13
  238. data/lib/active_record/type/binary.rb +0 -50
  239. data/lib/active_record/type/boolean.rb +0 -31
  240. data/lib/active_record/type/decimal.rb +0 -64
  241. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  242. data/lib/active_record/type/decorator.rb +0 -14
  243. data/lib/active_record/type/float.rb +0 -19
  244. data/lib/active_record/type/integer.rb +0 -59
  245. data/lib/active_record/type/mutable.rb +0 -16
  246. data/lib/active_record/type/numeric.rb +0 -36
  247. data/lib/active_record/type/string.rb +0 -40
  248. data/lib/active_record/type/text.rb +0 -11
  249. data/lib/active_record/type/time_value.rb +0 -38
  250. data/lib/active_record/type/unsigned_integer.rb +0 -15
  251. data/lib/active_record/type/value.rb +0 -110
@@ -81,6 +81,9 @@ module ActiveRecord
81
81
  #
82
82
  # Note that the model will _not_ be destroyed until the parent is saved.
83
83
  #
84
+ # Also note that the model will not be destroyed unless you also specify
85
+ # its id in the updated hash.
86
+ #
84
87
  # === One-to-many
85
88
  #
86
89
  # Consider a member that has a number of posts:
@@ -111,7 +114,7 @@ module ActiveRecord
111
114
  # member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
112
115
  # member.posts.second.title # => 'The egalitarian assumption of the modern citizen'
113
116
  #
114
- # You may also set a :reject_if proc to silently ignore any new record
117
+ # You may also set a +:reject_if+ proc to silently ignore any new record
115
118
  # hashes if they fail to pass your criteria. For example, the previous
116
119
  # example could be rewritten as:
117
120
  #
@@ -133,7 +136,7 @@ module ActiveRecord
133
136
  # member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
134
137
  # member.posts.second.title # => 'The egalitarian assumption of the modern citizen'
135
138
  #
136
- # Alternatively, :reject_if also accepts a symbol for using methods:
139
+ # Alternatively, +:reject_if+ also accepts a symbol for using methods:
137
140
  #
138
141
  # class Member < ActiveRecord::Base
139
142
  # has_many :posts
@@ -144,8 +147,8 @@ module ActiveRecord
144
147
  # has_many :posts
145
148
  # accepts_nested_attributes_for :posts, reject_if: :reject_posts
146
149
  #
147
- # def reject_posts(attributed)
148
- # attributed['title'].blank?
150
+ # def reject_posts(attributes)
151
+ # attributes['title'].blank?
149
152
  # end
150
153
  # end
151
154
  #
@@ -163,6 +166,11 @@ module ActiveRecord
163
166
  # member.posts.first.title # => '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!'
164
167
  # member.posts.second.title # => '[UPDATED] other post'
165
168
  #
169
+ # However, the above applies if the parent model is being updated as well.
170
+ # For example, If you wanted to create a +member+ named _joe_ and wanted to
171
+ # update the +posts+ at the same time, that would give an
172
+ # ActiveRecord::RecordNotFound error.
173
+ #
166
174
  # By default the associated records are protected from being destroyed. If
167
175
  # you want to destroy any of the associated records through the attributes
168
176
  # hash, you have to enable it first using the <tt>:allow_destroy</tt>
@@ -187,38 +195,46 @@ module ActiveRecord
187
195
  # Nested attributes for an associated collection can also be passed in
188
196
  # the form of a hash of hashes instead of an array of hashes:
189
197
  #
190
- # Member.create(name: 'joe',
191
- # posts_attributes: { first: { title: 'Foo' },
192
- # second: { title: 'Bar' } })
198
+ # Member.create(
199
+ # name: 'joe',
200
+ # posts_attributes: {
201
+ # first: { title: 'Foo' },
202
+ # second: { title: 'Bar' }
203
+ # }
204
+ # )
193
205
  #
194
206
  # has the same effect as
195
207
  #
196
- # Member.create(name: 'joe',
197
- # posts_attributes: [ { title: 'Foo' },
198
- # { title: 'Bar' } ])
208
+ # Member.create(
209
+ # name: 'joe',
210
+ # posts_attributes: [
211
+ # { title: 'Foo' },
212
+ # { title: 'Bar' }
213
+ # ]
214
+ # )
199
215
  #
200
216
  # The keys of the hash which is the value for +:posts_attributes+ are
201
217
  # ignored in this case.
202
- # However, it is not allowed to use +'id'+ or +:id+ for one of
218
+ # However, it is not allowed to use <tt>'id'</tt> or <tt>:id</tt> for one of
203
219
  # such keys, otherwise the hash will be wrapped in an array and
204
220
  # interpreted as an attribute hash for a single post.
205
221
  #
206
222
  # Passing attributes for an associated collection in the form of a hash
207
223
  # of hashes can be used with hashes generated from HTTP/HTML parameters,
208
- # where there maybe no natural way to submit an array of hashes.
224
+ # where there may be no natural way to submit an array of hashes.
209
225
  #
210
226
  # === Saving
211
227
  #
212
228
  # All changes to models, including the destruction of those marked for
213
229
  # destruction, are saved and destroyed automatically and atomically when
214
230
  # the parent model is saved. This happens inside the transaction initiated
215
- # by the parents save method. See ActiveRecord::AutosaveAssociation.
231
+ # by the parent's save method. See ActiveRecord::AutosaveAssociation.
216
232
  #
217
233
  # === Validating the presence of a parent model
218
234
  #
219
235
  # If you want to validate that a child record is associated with a parent
220
- # record, you can use <tt>validates_presence_of</tt> and
221
- # <tt>inverse_of</tt> as this example illustrates:
236
+ # record, you can use the +validates_presence_of+ method and the +:inverse_of+
237
+ # key as this example illustrates:
222
238
  #
223
239
  # class Member < ActiveRecord::Base
224
240
  # has_many :posts, inverse_of: :member
@@ -230,7 +246,7 @@ module ActiveRecord
230
246
  # validates_presence_of :member
231
247
  # end
232
248
  #
233
- # Note that if you do not specify the <tt>inverse_of</tt> option, then
249
+ # Note that if you do not specify the +:inverse_of+ option, then
234
250
  # Active Record will try to automatically guess the inverse association
235
251
  # based on heuristics.
236
252
  #
@@ -264,29 +280,31 @@ module ActiveRecord
264
280
  # Allows you to specify a Proc or a Symbol pointing to a method
265
281
  # that checks whether a record should be built for a certain attribute
266
282
  # hash. The hash is passed to the supplied Proc or the method
267
- # and it should return either +true+ or +false+. When no :reject_if
283
+ # and it should return either +true+ or +false+. When no +:reject_if+
268
284
  # is specified, a record will be built for all attribute hashes that
269
285
  # do not have a <tt>_destroy</tt> value that evaluates to true.
270
286
  # Passing <tt>:all_blank</tt> instead of a Proc will create a proc
271
287
  # that will reject a record where all the attributes are blank excluding
272
- # any value for _destroy.
288
+ # any value for +_destroy+.
273
289
  # [:limit]
274
- # Allows you to specify the maximum number of the associated records that
275
- # can be processed with the nested attributes. Limit also can be specified as a
276
- # Proc or a Symbol pointing to a method that should return number. If the size of the
277
- # nested attributes array exceeds the specified limit, NestedAttributes::TooManyRecords
278
- # exception is raised. If omitted, any number associations can be processed.
279
- # Note that the :limit option is only applicable to one-to-many associations.
290
+ # Allows you to specify the maximum number of associated records that
291
+ # can be processed with the nested attributes. Limit also can be specified
292
+ # as a Proc or a Symbol pointing to a method that should return a number.
293
+ # If the size of the nested attributes array exceeds the specified limit,
294
+ # NestedAttributes::TooManyRecords exception is raised. If omitted, any
295
+ # number of associations can be processed.
296
+ # Note that the +:limit+ option is only applicable to one-to-many
297
+ # associations.
280
298
  # [:update_only]
281
299
  # For a one-to-one association, this option allows you to specify how
282
- # nested attributes are to be used when an associated record already
300
+ # nested attributes are going to be used when an associated record already
283
301
  # exists. In general, an existing record may either be updated with the
284
302
  # new set of attribute values or be replaced by a wholly new record
285
- # containing those values. By default the :update_only option is +false+
303
+ # containing those values. By default the +:update_only+ option is +false+
286
304
  # and the nested attributes are used to update the existing record only
287
305
  # if they include the record's <tt>:id</tt> value. Otherwise a new
288
306
  # record will be instantiated and used to replace the existing one.
289
- # However if the :update_only option is +true+, the nested attributes
307
+ # However if the +:update_only+ option is +true+, the nested attributes
290
308
  # are used to update the record's attributes always, regardless of
291
309
  # whether the <tt>:id</tt> is present. The option is ignored for collection
292
310
  # associations.
@@ -376,6 +394,9 @@ module ActiveRecord
376
394
  # then the existing record will be marked for destruction.
377
395
  def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
378
396
  options = self.nested_attributes_options[association_name]
397
+ if attributes.respond_to?(:permitted?)
398
+ attributes = attributes.to_h
399
+ end
379
400
  attributes = attributes.with_indifferent_access
380
401
  existing_record = send(association_name)
381
402
 
@@ -432,6 +453,9 @@ module ActiveRecord
432
453
  # ])
433
454
  def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
434
455
  options = self.nested_attributes_options[association_name]
456
+ if attributes_collection.respond_to?(:permitted?)
457
+ attributes_collection = attributes_collection.to_h
458
+ end
435
459
 
436
460
  unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
437
461
  raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
@@ -458,6 +482,9 @@ module ActiveRecord
458
482
  end
459
483
 
460
484
  attributes_collection.each do |attributes|
485
+ if attributes.respond_to?(:permitted?)
486
+ attributes = attributes.to_h
487
+ end
461
488
  attributes = attributes.with_indifferent_access
462
489
 
463
490
  if attributes['id'].blank?
@@ -516,7 +543,7 @@ module ActiveRecord
516
543
 
517
544
  # Determines if a hash contains a truthy _destroy key.
518
545
  def has_destroy_flag?(hash)
519
- Type::Boolean.new.type_cast_from_user(hash['_destroy'])
546
+ Type::Boolean.new.cast(hash['_destroy'])
520
547
  end
521
548
 
522
549
  # Determines if a new record should be rejected by checking
@@ -552,7 +579,9 @@ module ActiveRecord
552
579
  end
553
580
 
554
581
  def raise_nested_attributes_record_not_found!(association_name, record_id)
555
- raise RecordNotFound, "Couldn't find #{self.class._reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
582
+ model = self.class._reflect_on_association(association_name).klass.name
583
+ raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
584
+ model, 'id', record_id)
556
585
  end
557
586
  end
558
587
  end
@@ -45,6 +45,10 @@ module ActiveRecord
45
45
  NoTouching.applied_to?(self.class)
46
46
  end
47
47
 
48
+ def touch_later(*) # :nodoc:
49
+ super unless no_touching?
50
+ end
51
+
48
52
  def touch(*) # :nodoc:
49
53
  super unless no_touching?
50
54
  end
@@ -1,9 +1,7 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  module ActiveRecord
4
2
  module NullRelation # :nodoc:
5
3
  def exec_queries
6
- @records = []
4
+ @records = [].freeze
7
5
  end
8
6
 
9
7
  def pluck(*column_names)
@@ -14,7 +12,7 @@ module ActiveRecord
14
12
  0
15
13
  end
16
14
 
17
- def update_all(_updates, _conditions = nil, _options = {})
15
+ def update_all(_updates)
18
16
  0
19
17
  end
20
18
 
@@ -30,10 +28,18 @@ module ActiveRecord
30
28
  true
31
29
  end
32
30
 
31
+ def none?
32
+ true
33
+ end
34
+
33
35
  def any?
34
36
  false
35
37
  end
36
38
 
39
+ def one?
40
+ false
41
+ end
42
+
37
43
  def many?
38
44
  false
39
45
  end
@@ -62,9 +68,7 @@ module ActiveRecord
62
68
  calculate :maximum, nil
63
69
  end
64
70
 
65
- def calculate(operation, _column_name, _options = {})
66
- # TODO: Remove _options argument as soon we remove support to
67
- # activerecord-deprecated_finders.
71
+ def calculate(operation, _column_name)
68
72
  if [:count, :sum, :size].include? operation
69
73
  group_values.any? ? Hash.new : 0
70
74
  elsif [:average, :minimum, :maximum].include?(operation) && group_values.any?
@@ -74,8 +78,12 @@ module ActiveRecord
74
78
  end
75
79
  end
76
80
 
77
- def exists?(_id = false)
81
+ def exists?(_conditions = :none)
78
82
  false
79
83
  end
84
+
85
+ def or(other)
86
+ other.spawn
87
+ end
80
88
  end
81
89
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
- # = Active Record Persistence
2
+ # = Active Record \Persistence
3
3
  module Persistence
4
4
  extend ActiveSupport::Concern
5
5
 
@@ -61,12 +61,12 @@ module ActiveRecord
61
61
  # +instantiate+ instead of +new+, finder methods ensure they get new
62
62
  # instances of the appropriate class for each record.
63
63
  #
64
- # See +ActiveRecord::Inheritance#discriminate_class_for_record+ to see
64
+ # See <tt>ActiveRecord::Inheritance#discriminate_class_for_record</tt> to see
65
65
  # how this "single-table" inheritance mapping is implemented.
66
- def instantiate(attributes, column_types = {})
66
+ def instantiate(attributes, column_types = {}, &block)
67
67
  klass = discriminate_class_for_record(attributes)
68
68
  attributes = klass.attributes_builder.build_from_database(attributes, column_types)
69
- klass.allocate.init_with('attributes' => attributes, 'new_record' => false)
69
+ klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
70
70
  end
71
71
 
72
72
  private
@@ -96,50 +96,68 @@ module ActiveRecord
96
96
  # Returns true if the record is persisted, i.e. it's not a new record and it was
97
97
  # not destroyed, otherwise returns false.
98
98
  def persisted?
99
- !(new_record? || destroyed?)
99
+ sync_with_transaction_state
100
+ !(@new_record || @destroyed)
100
101
  end
101
102
 
103
+ ##
104
+ # :call-seq:
105
+ # save(*args)
106
+ #
102
107
  # Saves the model.
103
108
  #
104
- # If the model is new a record gets created in the database, otherwise
109
+ # If the model is new, a record gets created in the database, otherwise
105
110
  # the existing record gets updated.
106
111
  #
107
- # By default, save always run validations. If any of them fail the action
108
- # is cancelled and +save+ returns +false+. However, if you supply
112
+ # By default, save always runs validations. If any of them fail the action
113
+ # is cancelled and #save returns +false+, and the record won't be saved. However, if you supply
109
114
  # validate: false, validations are bypassed altogether. See
110
115
  # ActiveRecord::Validations for more information.
111
116
  #
112
- # There's a series of callbacks associated with +save+. If any of the
113
- # <tt>before_*</tt> callbacks return +false+ the action is cancelled and
114
- # +save+ returns +false+. See ActiveRecord::Callbacks for further
117
+ # By default, #save also sets the +updated_at+/+updated_on+ attributes to
118
+ # the current time. However, if you supply <tt>touch: false</tt>, these
119
+ # timestamps will not be updated.
120
+ #
121
+ # There's a series of callbacks associated with #save. If any of the
122
+ # <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled and
123
+ # #save returns +false+. See ActiveRecord::Callbacks for further
115
124
  # details.
116
125
  #
117
126
  # Attributes marked as readonly are silently ignored if the record is
118
127
  # being updated.
119
- def save(*)
120
- create_or_update
128
+ def save(*args, &block)
129
+ create_or_update(*args, &block)
121
130
  rescue ActiveRecord::RecordInvalid
122
131
  false
123
132
  end
124
133
 
134
+ ##
135
+ # :call-seq:
136
+ # save!(*args)
137
+ #
125
138
  # Saves the model.
126
139
  #
127
- # If the model is new a record gets created in the database, otherwise
140
+ # If the model is new, a record gets created in the database, otherwise
128
141
  # the existing record gets updated.
129
142
  #
130
- # With <tt>save!</tt> validations always run. If any of them fail
131
- # ActiveRecord::RecordInvalid gets raised. See ActiveRecord::Validations
132
- # for more information.
143
+ # By default, #save! always runs validations. If any of them fail
144
+ # ActiveRecord::RecordInvalid gets raised, and the record won't be saved. However, if you supply
145
+ # validate: false, validations are bypassed altogether. See
146
+ # ActiveRecord::Validations for more information.
147
+ #
148
+ # By default, #save! also sets the +updated_at+/+updated_on+ attributes to
149
+ # the current time. However, if you supply <tt>touch: false</tt>, these
150
+ # timestamps will not be updated.
133
151
  #
134
- # There's a series of callbacks associated with <tt>save!</tt>. If any of
135
- # the <tt>before_*</tt> callbacks return +false+ the action is cancelled
136
- # and <tt>save!</tt> raises ActiveRecord::RecordNotSaved. See
152
+ # There's a series of callbacks associated with #save!. If any of
153
+ # the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
154
+ # and #save! raises ActiveRecord::RecordNotSaved. See
137
155
  # ActiveRecord::Callbacks for further details.
138
156
  #
139
157
  # Attributes marked as readonly are silently ignored if the record is
140
158
  # being updated.
141
- def save!(*)
142
- create_or_update || raise(RecordNotSaved.new("Failed to save the record", self))
159
+ def save!(*args, &block)
160
+ create_or_update(*args, &block) || raise(RecordNotSaved.new("Failed to save the record", self))
143
161
  end
144
162
 
145
163
  # Deletes the record in the database and freezes this instance to
@@ -149,6 +167,8 @@ module ActiveRecord
149
167
  # The row is simply removed with an SQL +DELETE+ statement on the
150
168
  # record's primary key, and no callbacks are executed.
151
169
  #
170
+ # Note that this will also delete records marked as {#readonly?}[rdoc-ref:Core#readonly?].
171
+ #
152
172
  # To enforce the object's +before_destroy+ and +after_destroy+
153
173
  # callbacks or any <tt>:dependent</tt> association
154
174
  # options, use <tt>#destroy</tt>.
@@ -161,10 +181,10 @@ module ActiveRecord
161
181
  # Deletes the record in the database and freezes this instance to reflect
162
182
  # that no changes should be made (since they can't be persisted).
163
183
  #
164
- # There's a series of callbacks associated with <tt>destroy</tt>. If
165
- # the <tt>before_destroy</tt> callback return +false+ the action is cancelled
166
- # and <tt>destroy</tt> returns +false+. See
167
- # ActiveRecord::Callbacks for further details.
184
+ # There's a series of callbacks associated with #destroy. If the
185
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
186
+ # and #destroy returns +false+.
187
+ # See ActiveRecord::Callbacks for further details.
168
188
  def destroy
169
189
  raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
170
190
  destroy_associations
@@ -177,12 +197,12 @@ module ActiveRecord
177
197
  # Deletes the record in the database and freezes this instance to reflect
178
198
  # that no changes should be made (since they can't be persisted).
179
199
  #
180
- # There's a series of callbacks associated with <tt>destroy!</tt>. If
181
- # the <tt>before_destroy</tt> callback return +false+ the action is cancelled
182
- # and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
183
- # ActiveRecord::Callbacks for further details.
200
+ # There's a series of callbacks associated with #destroy!. If the
201
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
202
+ # and #destroy! raises ActiveRecord::RecordNotDestroyed.
203
+ # See ActiveRecord::Callbacks for further details.
184
204
  def destroy!
185
- destroy || raise(RecordNotDestroyed.new("Failed to destroy the record", self))
205
+ destroy || _raise_record_not_destroyed
186
206
  end
187
207
 
188
208
  # Returns an instance of the specified +klass+ with the attributes of the
@@ -194,19 +214,21 @@ module ActiveRecord
194
214
  # instance using the companies/company partial instead of clients/client.
195
215
  #
196
216
  # Note: The new instance will share a link to the same attributes as the original class.
197
- # So any change to the attributes in either instance will affect the other.
217
+ # Therefore the sti column value will still be the same.
218
+ # Any change to the attributes on either instance will affect both instances.
219
+ # If you want to change the sti column as well, use #becomes! instead.
198
220
  def becomes(klass)
199
221
  became = klass.new
200
222
  became.instance_variable_set("@attributes", @attributes)
201
- changed_attributes = @changed_attributes if defined?(@changed_attributes)
202
- became.instance_variable_set("@changed_attributes", changed_attributes || {})
223
+ became.instance_variable_set("@mutation_tracker", @mutation_tracker) if defined?(@mutation_tracker)
224
+ became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
203
225
  became.instance_variable_set("@new_record", new_record?)
204
226
  became.instance_variable_set("@destroyed", destroyed?)
205
- became.instance_variable_set("@errors", errors)
227
+ became.errors.copy!(errors)
206
228
  became
207
229
  end
208
230
 
209
- # Wrapper around +becomes+ that also changes the instance's sti column value.
231
+ # Wrapper around #becomes that also changes the instance's sti column value.
210
232
  # This is especially useful if you want to persist the changed class in your
211
233
  # database.
212
234
  #
@@ -226,19 +248,20 @@ module ActiveRecord
226
248
  # This is especially useful for boolean flags on existing records. Also note that
227
249
  #
228
250
  # * Validation is skipped.
229
- # * Callbacks are invoked.
251
+ # * \Callbacks are invoked.
230
252
  # * updated_at/updated_on column is updated if that column is available.
231
253
  # * Updates all the attributes that are dirty in this object.
232
254
  #
233
- # This method raises an +ActiveRecord::ActiveRecordError+ if the
255
+ # This method raises an ActiveRecord::ActiveRecordError if the
234
256
  # attribute is marked as readonly.
235
257
  #
236
- # See also +update_column+.
258
+ # Also see #update_column.
237
259
  def update_attribute(name, value)
238
260
  name = name.to_s
239
261
  verify_readonly_attribute(name)
240
- send("#{name}=", value)
241
- save(validate: false)
262
+ public_send("#{name}=", value)
263
+
264
+ changed? ? save(validate: false) : true
242
265
  end
243
266
 
244
267
  # Updates the attributes of the model from the passed-in hash and saves the
@@ -255,8 +278,8 @@ module ActiveRecord
255
278
 
256
279
  alias update_attributes update
257
280
 
258
- # Updates its receiver just like +update+ but calls <tt>save!</tt> instead
259
- # of +save+, so an exception is raised if the record is invalid.
281
+ # Updates its receiver just like #update but calls #save! instead
282
+ # of +save+, so an exception is raised if the record is invalid and saving will fail.
260
283
  def update!(attributes)
261
284
  # The following transaction covers any possible database side-effects of the
262
285
  # attributes assignment. For example, setting the IDs of a child collection.
@@ -282,11 +305,12 @@ module ActiveRecord
282
305
  # the database, but take into account that in consequence the regular update
283
306
  # procedures are totally bypassed. In particular:
284
307
  #
285
- # * Validations are skipped.
286
- # * Callbacks are skipped.
308
+ # * \Validations are skipped.
309
+ # * \Callbacks are skipped.
287
310
  # * +updated_at+/+updated_on+ are not updated.
311
+ # * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
288
312
  #
289
- # This method raises an +ActiveRecord::ActiveRecordError+ when called on new
313
+ # This method raises an ActiveRecord::ActiveRecordError when called on new
290
314
  # objects, or when at least one of the attributes is marked as readonly.
291
315
  def update_columns(attributes)
292
316
  raise ActiveRecordError, "cannot update a new record" if new_record?
@@ -314,42 +338,52 @@ module ActiveRecord
314
338
  self
315
339
  end
316
340
 
317
- # Wrapper around +increment+ that saves the record. This method differs from
318
- # its non-bang version in that it passes through the attribute setter.
319
- # Saving is not subjected to validation checks. Returns +true+ if the
320
- # record could be saved.
341
+ # Wrapper around #increment that writes the update to the database.
342
+ # Only +attribute+ is updated; the record itself is not saved.
343
+ # This means that any other modified attributes will still be dirty.
344
+ # Validations and callbacks are skipped. Returns +self+.
321
345
  def increment!(attribute, by = 1)
322
- increment(attribute, by).update_attribute(attribute, self[attribute])
346
+ increment(attribute, by)
347
+ change = public_send(attribute) - (attribute_was(attribute.to_s) || 0)
348
+ self.class.update_counters(id, attribute => change)
349
+ clear_attribute_change(attribute) # eww
350
+ self
323
351
  end
324
352
 
325
353
  # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
326
354
  # The decrement is performed directly on the underlying attribute, no setter is invoked.
327
355
  # Only makes sense for number-based attributes. Returns +self+.
328
356
  def decrement(attribute, by = 1)
329
- self[attribute] ||= 0
330
- self[attribute] -= by
331
- self
357
+ increment(attribute, -by)
332
358
  end
333
359
 
334
- # Wrapper around +decrement+ that saves the record. This method differs from
335
- # its non-bang version in that it passes through the attribute setter.
336
- # Saving is not subjected to validation checks. Returns +true+ if the
337
- # record could be saved.
360
+ # Wrapper around #decrement that writes the update to the database.
361
+ # Only +attribute+ is updated; the record itself is not saved.
362
+ # This means that any other modified attributes will still be dirty.
363
+ # Validations and callbacks are skipped. Returns +self+.
338
364
  def decrement!(attribute, by = 1)
339
- decrement(attribute, by).update_attribute(attribute, self[attribute])
365
+ increment!(attribute, -by)
340
366
  end
341
367
 
342
368
  # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
343
369
  # if the predicate returns +true+ the attribute will become +false+. This
344
370
  # method toggles directly the underlying value without calling any setter.
345
371
  # Returns +self+.
372
+ #
373
+ # Example:
374
+ #
375
+ # user = User.first
376
+ # user.banned? # => false
377
+ # user.toggle(:banned)
378
+ # user.banned? # => true
379
+ #
346
380
  def toggle(attribute)
347
- self[attribute] = !send("#{attribute}?")
381
+ self[attribute] = !public_send("#{attribute}?")
348
382
  self
349
383
  end
350
384
 
351
- # Wrapper around +toggle+ that saves the record. This method differs from
352
- # its non-bang version in that it passes through the attribute setter.
385
+ # Wrapper around #toggle that saves the record. This method differs from
386
+ # its non-bang version in the sense that it passes through the attribute setter.
353
387
  # Saving is not subjected to validation checks. Returns +true+ if the
354
388
  # record could be saved.
355
389
  def toggle!(attribute)
@@ -371,7 +405,7 @@ module ActiveRecord
371
405
  # Attributes are reloaded from the database, and caches busted, in
372
406
  # particular the associations cache and the QueryCache.
373
407
  #
374
- # If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt>
408
+ # If the record no longer exists in the database ActiveRecord::RecordNotFound
375
409
  # is raised. Otherwise, in addition to the in-place modification the method
376
410
  # returns +self+ for convenience.
377
411
  #
@@ -405,8 +439,6 @@ module ActiveRecord
405
439
  # end
406
440
  #
407
441
  def reload(options = nil)
408
- clear_aggregation_cache
409
- clear_association_cache
410
442
  self.class.connection.clear_query_cache
411
443
 
412
444
  fresh_object =
@@ -421,19 +453,22 @@ module ActiveRecord
421
453
  self
422
454
  end
423
455
 
424
- # Saves the record with the updated_at/on attributes set to the current time.
456
+ # Saves the record with the updated_at/on attributes set to the current time
457
+ # or the time specified.
425
458
  # Please note that no validation is performed and only the +after_touch+,
426
459
  # +after_commit+ and +after_rollback+ callbacks are executed.
427
460
  #
461
+ # This method can be passed attribute names and an optional time argument.
428
462
  # If attribute names are passed, they are updated along with updated_at/on
429
- # attributes.
463
+ # attributes. If no time argument is passed, the current time is used as default.
430
464
  #
431
- # product.touch # updates updated_at/on
465
+ # product.touch # updates updated_at/on with current time
466
+ # product.touch(time: Time.new(2015, 2, 16, 0, 0, 0)) # updates updated_at/on with specified time
432
467
  # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
433
468
  # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
434
469
  #
435
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
436
- # associated object.
470
+ # If used along with {belongs_to}[rdoc-ref:Associations::ClassMethods#belongs_to]
471
+ # then +touch+ will invoke +touch+ method on associated object.
437
472
  #
438
473
  # class Brake < ActiveRecord::Base
439
474
  # belongs_to :car, touch: true
@@ -452,26 +487,43 @@ module ActiveRecord
452
487
  # ball = Ball.new
453
488
  # ball.touch(:updated_at) # => raises ActiveRecordError
454
489
  #
455
- def touch(*names)
456
- raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
490
+ def touch(*names, time: nil)
491
+ unless persisted?
492
+ raise ActiveRecordError, <<-MSG.squish
493
+ cannot touch on a new or destroyed record object. Consider using
494
+ persisted?, new_record?, or destroyed? before touching
495
+ MSG
496
+ end
457
497
 
498
+ time ||= current_time_from_proper_timezone
458
499
  attributes = timestamp_attributes_for_update_in_model
459
500
  attributes.concat(names)
460
501
 
461
502
  unless attributes.empty?
462
- current_time = current_time_from_proper_timezone
463
503
  changes = {}
464
504
 
465
505
  attributes.each do |column|
466
506
  column = column.to_s
467
- changes[column] = write_attribute(column, current_time)
507
+ changes[column] = write_attribute(column, time)
468
508
  end
469
509
 
470
- changes[self.class.locking_column] = increment_lock if locking_enabled?
471
-
472
510
  clear_attribute_changes(changes.keys)
473
511
  primary_key = self.class.primary_key
474
- self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
512
+ scope = self.class.unscoped.where(primary_key => _read_attribute(primary_key))
513
+
514
+ if locking_enabled?
515
+ locking_column = self.class.locking_column
516
+ scope = scope.where(locking_column => _read_attribute(locking_column))
517
+ changes[locking_column] = increment_lock
518
+ end
519
+
520
+ result = scope.update_all(changes) == 1
521
+
522
+ if !result && locking_enabled?
523
+ raise ActiveRecord::StaleObjectError.new(self, "touch")
524
+ end
525
+
526
+ result
475
527
  else
476
528
  true
477
529
  end
@@ -488,20 +540,12 @@ module ActiveRecord
488
540
  end
489
541
 
490
542
  def relation_for_destroy
491
- pk = self.class.primary_key
492
- column = self.class.columns_hash[pk]
493
- substitute = self.class.connection.substitute_at(column)
494
-
495
- relation = self.class.unscoped.where(
496
- self.class.arel_table[pk].eq(substitute))
497
-
498
- relation.bind_values = [[column, id]]
499
- relation
543
+ self.class.unscoped.where(self.class.primary_key => id)
500
544
  end
501
545
 
502
- def create_or_update
546
+ def create_or_update(*args, &block)
503
547
  raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
504
- result = new_record? ? _create_record : _update_record
548
+ result = new_record? ? _create_record(&block) : _update_record(*args, &block)
505
549
  result != false
506
550
  end
507
551
 
@@ -510,10 +554,14 @@ module ActiveRecord
510
554
  def _update_record(attribute_names = self.attribute_names)
511
555
  attributes_values = arel_attributes_with_values_for_update(attribute_names)
512
556
  if attributes_values.empty?
513
- 0
557
+ rows_affected = 0
514
558
  else
515
- self.class.unscoped._update_record attributes_values, id, id_was
559
+ rows_affected = self.class.unscoped._update_record attributes_values, id, id_was
516
560
  end
561
+
562
+ yield(self) if block_given?
563
+
564
+ rows_affected
517
565
  end
518
566
 
519
567
  # Creates a record with values matching those of the instance attributes
@@ -525,11 +573,25 @@ module ActiveRecord
525
573
  self.id ||= new_id if self.class.primary_key
526
574
 
527
575
  @new_record = false
576
+
577
+ yield(self) if block_given?
578
+
528
579
  id
529
580
  end
530
581
 
531
582
  def verify_readonly_attribute(name)
532
583
  raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
533
584
  end
585
+
586
+ def _raise_record_not_destroyed
587
+ @_association_destroy_exception ||= nil
588
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy the record", self)
589
+ ensure
590
+ @_association_destroy_exception = nil
591
+ end
592
+
593
+ def belongs_to_touch_method
594
+ :touch
595
+ end
534
596
  end
535
597
  end