activerecord 4.2.11.1 → 5.0.0

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 (246) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1282 -1195
  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 +8 -4
  8. data/lib/active_record/aggregations.rb +35 -24
  9. data/lib/active_record/association_relation.rb +3 -3
  10. data/lib/active_record/associations.rb +317 -209
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +11 -9
  13. data/lib/active_record/associations/association_scope.rb +73 -102
  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 +14 -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 +3 -10
  22. data/lib/active_record/associations/collection_association.rb +49 -41
  23. data/lib/active_record/associations/collection_proxy.rb +67 -27
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +20 -71
  26. data/lib/active_record/associations/has_many_through_association.rb +8 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +29 -19
  29. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  30. data/lib/active_record/associations/preloader.rb +14 -4
  31. data/lib/active_record/associations/preloader/association.rb +46 -52
  32. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  33. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  34. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  35. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  36. data/lib/active_record/associations/singular_association.rb +7 -1
  37. data/lib/active_record/associations/through_association.rb +11 -3
  38. data/lib/active_record/attribute.rb +68 -18
  39. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  40. data/lib/active_record/attribute_assignment.rb +19 -140
  41. data/lib/active_record/attribute_decorators.rb +6 -5
  42. data/lib/active_record/attribute_methods.rb +76 -47
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  44. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  45. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  46. data/lib/active_record/attribute_methods/query.rb +2 -2
  47. data/lib/active_record/attribute_methods/read.rb +31 -59
  48. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  50. data/lib/active_record/attribute_methods/write.rb +13 -37
  51. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  52. data/lib/active_record/attribute_set.rb +30 -3
  53. data/lib/active_record/attribute_set/builder.rb +6 -4
  54. data/lib/active_record/attributes.rb +199 -81
  55. data/lib/active_record/autosave_association.rb +49 -16
  56. data/lib/active_record/base.rb +32 -23
  57. data/lib/active_record/callbacks.rb +39 -43
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +20 -8
  60. data/lib/active_record/collection_cache_key.rb +40 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
  62. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  63. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
  64. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
  65. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
  66. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  67. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  68. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
  69. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  70. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
  71. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  72. data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
  73. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
  74. data/lib/active_record/connection_adapters/column.rb +28 -43
  75. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  76. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  77. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  78. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  79. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  80. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  84. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  85. data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
  86. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  87. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
  88. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -57
  91. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  100. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +37 -14
  121. data/lib/active_record/core.rb +89 -107
  122. data/lib/active_record/counter_cache.rb +13 -24
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +113 -76
  125. data/lib/active_record/errors.rb +87 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +76 -40
  130. data/lib/active_record/gem_version.rb +4 -4
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +15 -15
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration.rb +363 -133
  140. data/lib/active_record/migration/command_recorder.rb +59 -18
  141. data/lib/active_record/migration/compatibility.rb +126 -0
  142. data/lib/active_record/model_schema.rb +129 -41
  143. data/lib/active_record/nested_attributes.rb +58 -29
  144. data/lib/active_record/null_relation.rb +16 -8
  145. data/lib/active_record/persistence.rb +121 -80
  146. data/lib/active_record/query_cache.rb +15 -18
  147. data/lib/active_record/querying.rb +10 -9
  148. data/lib/active_record/railtie.rb +23 -16
  149. data/lib/active_record/railties/controller_runtime.rb +1 -1
  150. data/lib/active_record/railties/databases.rake +69 -46
  151. data/lib/active_record/readonly_attributes.rb +1 -1
  152. data/lib/active_record/reflection.rb +282 -115
  153. data/lib/active_record/relation.rb +176 -116
  154. data/lib/active_record/relation/batches.rb +139 -34
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  156. data/lib/active_record/relation/calculations.rb +79 -108
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +163 -81
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +16 -42
  161. data/lib/active_record/relation/predicate_builder.rb +120 -107
  162. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  163. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  164. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  166. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  167. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  168. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  169. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +308 -244
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +4 -7
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/result.rb +4 -3
  177. data/lib/active_record/runtime_registry.rb +1 -1
  178. data/lib/active_record/sanitization.rb +95 -66
  179. data/lib/active_record/schema.rb +26 -22
  180. data/lib/active_record/schema_dumper.rb +62 -38
  181. data/lib/active_record/schema_migration.rb +11 -14
  182. data/lib/active_record/scoping.rb +32 -15
  183. data/lib/active_record/scoping/default.rb +23 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/secure_token.rb +38 -0
  186. data/lib/active_record/serialization.rb +2 -4
  187. data/lib/active_record/statement_cache.rb +16 -14
  188. data/lib/active_record/store.rb +8 -3
  189. data/lib/active_record/suppressor.rb +58 -0
  190. data/lib/active_record/table_metadata.rb +68 -0
  191. data/lib/active_record/tasks/database_tasks.rb +57 -43
  192. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  193. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  194. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  195. data/lib/active_record/timestamp.rb +20 -9
  196. data/lib/active_record/touch_later.rb +58 -0
  197. data/lib/active_record/transactions.rb +138 -56
  198. data/lib/active_record/type.rb +66 -17
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -45
  201. data/lib/active_record/type/date_time.rb +2 -49
  202. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  203. data/lib/active_record/type/internal/timezone.rb +15 -0
  204. data/lib/active_record/type/serialized.rb +15 -14
  205. data/lib/active_record/type/time.rb +10 -16
  206. data/lib/active_record/type/type_map.rb +4 -4
  207. data/lib/active_record/type_caster.rb +7 -0
  208. data/lib/active_record/type_caster/connection.rb +29 -0
  209. data/lib/active_record/type_caster/map.rb +19 -0
  210. data/lib/active_record/validations.rb +33 -32
  211. data/lib/active_record/validations/absence.rb +23 -0
  212. data/lib/active_record/validations/associated.rb +10 -3
  213. data/lib/active_record/validations/length.rb +24 -0
  214. data/lib/active_record/validations/presence.rb +11 -12
  215. data/lib/active_record/validations/uniqueness.rb +30 -29
  216. data/lib/rails/generators/active_record/migration.rb +7 -0
  217. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  218. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  219. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  220. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  221. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  222. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  223. metadata +59 -34
  224. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  225. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  226. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  227. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  228. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  229. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  231. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  232. data/lib/active_record/type/big_integer.rb +0 -13
  233. data/lib/active_record/type/binary.rb +0 -50
  234. data/lib/active_record/type/boolean.rb +0 -31
  235. data/lib/active_record/type/decimal.rb +0 -64
  236. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  237. data/lib/active_record/type/decorator.rb +0 -14
  238. data/lib/active_record/type/float.rb +0 -19
  239. data/lib/active_record/type/integer.rb +0 -59
  240. data/lib/active_record/type/mutable.rb +0 -16
  241. data/lib/active_record/type/numeric.rb +0 -36
  242. data/lib/active_record/type/string.rb +0 -40
  243. data/lib/active_record/type/text.rb +0 -11
  244. data/lib/active_record/type/time_value.rb +0 -38
  245. data/lib/active_record/type/unsigned_integer.rb +0 -15
  246. 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
@@ -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,7 +61,7 @@ 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
66
  def instantiate(attributes, column_types = {})
67
67
  klass = discriminate_class_for_record(attributes)
@@ -96,50 +96,60 @@ 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
 
102
103
  # Saves the model.
103
104
  #
104
- # If the model is new a record gets created in the database, otherwise
105
+ # If the model is new, a record gets created in the database, otherwise
105
106
  # the existing record gets updated.
106
107
  #
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
108
+ # By default, save always runs validations. If any of them fail the action
109
+ # is cancelled and #save returns +false+, and the record won't be saved. However, if you supply
109
110
  # validate: false, validations are bypassed altogether. See
110
111
  # ActiveRecord::Validations for more information.
111
112
  #
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
113
+ # By default, #save also sets the +updated_at+/+updated_on+ attributes to
114
+ # the current time. However, if you supply <tt>touch: false</tt>, these
115
+ # timestamps will not be updated.
116
+ #
117
+ # There's a series of callbacks associated with #save. If any of the
118
+ # <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled and
119
+ # #save returns +false+. See ActiveRecord::Callbacks for further
115
120
  # details.
116
121
  #
117
122
  # Attributes marked as readonly are silently ignored if the record is
118
123
  # being updated.
119
- def save(*)
120
- create_or_update
124
+ def save(*args)
125
+ create_or_update(*args)
121
126
  rescue ActiveRecord::RecordInvalid
122
127
  false
123
128
  end
124
129
 
125
130
  # Saves the model.
126
131
  #
127
- # If the model is new a record gets created in the database, otherwise
132
+ # If the model is new, a record gets created in the database, otherwise
128
133
  # the existing record gets updated.
129
134
  #
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.
135
+ # By default, #save! always runs validations. If any of them fail
136
+ # ActiveRecord::RecordInvalid gets raised, and the record won't be saved. However, if you supply
137
+ # validate: false, validations are bypassed altogether. See
138
+ # ActiveRecord::Validations for more information.
139
+ #
140
+ # By default, #save! also sets the +updated_at+/+updated_on+ attributes to
141
+ # the current time. However, if you supply <tt>touch: false</tt>, these
142
+ # timestamps will not be updated.
133
143
  #
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
144
+ # There's a series of callbacks associated with #save!. If any of
145
+ # the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
146
+ # and #save! raises ActiveRecord::RecordNotSaved. See
137
147
  # ActiveRecord::Callbacks for further details.
138
148
  #
139
149
  # Attributes marked as readonly are silently ignored if the record is
140
150
  # being updated.
141
- def save!(*)
142
- create_or_update || raise(RecordNotSaved.new("Failed to save the record", self))
151
+ def save!(*args)
152
+ create_or_update(*args) || raise(RecordNotSaved.new("Failed to save the record", self))
143
153
  end
144
154
 
145
155
  # Deletes the record in the database and freezes this instance to
@@ -149,6 +159,8 @@ module ActiveRecord
149
159
  # The row is simply removed with an SQL +DELETE+ statement on the
150
160
  # record's primary key, and no callbacks are executed.
151
161
  #
162
+ # Note that this will also delete records marked as {#readonly?}[rdoc-ref:Core#readonly?].
163
+ #
152
164
  # To enforce the object's +before_destroy+ and +after_destroy+
153
165
  # callbacks or any <tt>:dependent</tt> association
154
166
  # options, use <tt>#destroy</tt>.
@@ -161,10 +173,10 @@ module ActiveRecord
161
173
  # Deletes the record in the database and freezes this instance to reflect
162
174
  # that no changes should be made (since they can't be persisted).
163
175
  #
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.
176
+ # There's a series of callbacks associated with #destroy. If the
177
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
178
+ # and #destroy returns +false+.
179
+ # See ActiveRecord::Callbacks for further details.
168
180
  def destroy
169
181
  raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
170
182
  destroy_associations
@@ -177,12 +189,12 @@ module ActiveRecord
177
189
  # Deletes the record in the database and freezes this instance to reflect
178
190
  # that no changes should be made (since they can't be persisted).
179
191
  #
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.
192
+ # There's a series of callbacks associated with #destroy!. If the
193
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
194
+ # and #destroy! raises ActiveRecord::RecordNotDestroyed.
195
+ # See ActiveRecord::Callbacks for further details.
184
196
  def destroy!
185
- destroy || raise(RecordNotDestroyed.new("Failed to destroy the record", self))
197
+ destroy || _raise_record_not_destroyed
186
198
  end
187
199
 
188
200
  # Returns an instance of the specified +klass+ with the attributes of the
@@ -194,19 +206,21 @@ module ActiveRecord
194
206
  # instance using the companies/company partial instead of clients/client.
195
207
  #
196
208
  # 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.
209
+ # Therefore the sti column value will still be the same.
210
+ # Any change to the attributes on either instance will affect both instances.
211
+ # If you want to change the sti column as well, use #becomes! instead.
198
212
  def becomes(klass)
199
213
  became = klass.new
200
214
  became.instance_variable_set("@attributes", @attributes)
201
- changed_attributes = @changed_attributes if defined?(@changed_attributes)
202
- became.instance_variable_set("@changed_attributes", changed_attributes || {})
215
+ became.instance_variable_set("@mutation_tracker", @mutation_tracker) if defined?(@mutation_tracker)
216
+ became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
203
217
  became.instance_variable_set("@new_record", new_record?)
204
218
  became.instance_variable_set("@destroyed", destroyed?)
205
- became.instance_variable_set("@errors", errors)
219
+ became.errors.copy!(errors)
206
220
  became
207
221
  end
208
222
 
209
- # Wrapper around +becomes+ that also changes the instance's sti column value.
223
+ # Wrapper around #becomes that also changes the instance's sti column value.
210
224
  # This is especially useful if you want to persist the changed class in your
211
225
  # database.
212
226
  #
@@ -226,19 +240,19 @@ module ActiveRecord
226
240
  # This is especially useful for boolean flags on existing records. Also note that
227
241
  #
228
242
  # * Validation is skipped.
229
- # * Callbacks are invoked.
243
+ # * \Callbacks are invoked.
230
244
  # * updated_at/updated_on column is updated if that column is available.
231
245
  # * Updates all the attributes that are dirty in this object.
232
246
  #
233
- # This method raises an +ActiveRecord::ActiveRecordError+ if the
247
+ # This method raises an ActiveRecord::ActiveRecordError if the
234
248
  # attribute is marked as readonly.
235
249
  #
236
- # See also +update_column+.
250
+ # Also see #update_column.
237
251
  def update_attribute(name, value)
238
252
  name = name.to_s
239
253
  verify_readonly_attribute(name)
240
- send("#{name}=", value)
241
- save(validate: false)
254
+ public_send("#{name}=", value)
255
+ save(validate: false) if changed?
242
256
  end
243
257
 
244
258
  # Updates the attributes of the model from the passed-in hash and saves the
@@ -255,8 +269,8 @@ module ActiveRecord
255
269
 
256
270
  alias update_attributes update
257
271
 
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.
272
+ # Updates its receiver just like #update but calls #save! instead
273
+ # of +save+, so an exception is raised if the record is invalid and saving will fail.
260
274
  def update!(attributes)
261
275
  # The following transaction covers any possible database side-effects of the
262
276
  # attributes assignment. For example, setting the IDs of a child collection.
@@ -282,11 +296,12 @@ module ActiveRecord
282
296
  # the database, but take into account that in consequence the regular update
283
297
  # procedures are totally bypassed. In particular:
284
298
  #
285
- # * Validations are skipped.
286
- # * Callbacks are skipped.
299
+ # * \Validations are skipped.
300
+ # * \Callbacks are skipped.
287
301
  # * +updated_at+/+updated_on+ are not updated.
302
+ # * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
288
303
  #
289
- # This method raises an +ActiveRecord::ActiveRecordError+ when called on new
304
+ # This method raises an ActiveRecord::ActiveRecordError when called on new
290
305
  # objects, or when at least one of the attributes is marked as readonly.
291
306
  def update_columns(attributes)
292
307
  raise ActiveRecordError, "cannot update a new record" if new_record?
@@ -314,42 +329,52 @@ module ActiveRecord
314
329
  self
315
330
  end
316
331
 
317
- # Wrapper around +increment+ that saves the record. This method differs from
332
+ # Wrapper around #increment that saves the record. This method differs from
318
333
  # its non-bang version in that it passes through the attribute setter.
319
334
  # Saving is not subjected to validation checks. Returns +true+ if the
320
335
  # record could be saved.
321
336
  def increment!(attribute, by = 1)
322
- increment(attribute, by).update_attribute(attribute, self[attribute])
337
+ increment(attribute, by)
338
+ change = public_send(attribute) - (attribute_was(attribute.to_s) || 0)
339
+ self.class.update_counters(id, attribute => change)
340
+ clear_attribute_change(attribute) # eww
341
+ self
323
342
  end
324
343
 
325
344
  # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
326
345
  # The decrement is performed directly on the underlying attribute, no setter is invoked.
327
346
  # Only makes sense for number-based attributes. Returns +self+.
328
347
  def decrement(attribute, by = 1)
329
- self[attribute] ||= 0
330
- self[attribute] -= by
331
- self
348
+ increment(attribute, -by)
332
349
  end
333
350
 
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.
351
+ # Wrapper around #decrement that saves the record. This method differs from
352
+ # its non-bang version in the sense that it passes through the attribute setter.
336
353
  # Saving is not subjected to validation checks. Returns +true+ if the
337
354
  # record could be saved.
338
355
  def decrement!(attribute, by = 1)
339
- decrement(attribute, by).update_attribute(attribute, self[attribute])
356
+ increment!(attribute, -by)
340
357
  end
341
358
 
342
359
  # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
343
360
  # if the predicate returns +true+ the attribute will become +false+. This
344
361
  # method toggles directly the underlying value without calling any setter.
345
362
  # Returns +self+.
363
+ #
364
+ # Example:
365
+ #
366
+ # user = User.first
367
+ # user.banned? # => false
368
+ # user.toggle(:banned)
369
+ # user.banned? # => true
370
+ #
346
371
  def toggle(attribute)
347
- self[attribute] = !send("#{attribute}?")
372
+ self[attribute] = !public_send("#{attribute}?")
348
373
  self
349
374
  end
350
375
 
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.
376
+ # Wrapper around #toggle that saves the record. This method differs from
377
+ # its non-bang version in the sense that it passes through the attribute setter.
353
378
  # Saving is not subjected to validation checks. Returns +true+ if the
354
379
  # record could be saved.
355
380
  def toggle!(attribute)
@@ -371,7 +396,7 @@ module ActiveRecord
371
396
  # Attributes are reloaded from the database, and caches busted, in
372
397
  # particular the associations cache and the QueryCache.
373
398
  #
374
- # If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt>
399
+ # If the record no longer exists in the database ActiveRecord::RecordNotFound
375
400
  # is raised. Otherwise, in addition to the in-place modification the method
376
401
  # returns +self+ for convenience.
377
402
  #
@@ -405,8 +430,6 @@ module ActiveRecord
405
430
  # end
406
431
  #
407
432
  def reload(options = nil)
408
- clear_aggregation_cache
409
- clear_association_cache
410
433
  self.class.connection.clear_query_cache
411
434
 
412
435
  fresh_object =
@@ -421,19 +444,22 @@ module ActiveRecord
421
444
  self
422
445
  end
423
446
 
424
- # Saves the record with the updated_at/on attributes set to the current time.
447
+ # Saves the record with the updated_at/on attributes set to the current time
448
+ # or the time specified.
425
449
  # Please note that no validation is performed and only the +after_touch+,
426
450
  # +after_commit+ and +after_rollback+ callbacks are executed.
427
451
  #
452
+ # This method can be passed attribute names and an optional time argument.
428
453
  # If attribute names are passed, they are updated along with updated_at/on
429
- # attributes.
454
+ # attributes. If no time argument is passed, the current time is used as default.
430
455
  #
431
- # product.touch # updates updated_at/on
456
+ # product.touch # updates updated_at/on with current time
457
+ # product.touch(time: Time.new(2015, 2, 16, 0, 0, 0)) # updates updated_at/on with specified time
432
458
  # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
433
459
  # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
434
460
  #
435
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
436
- # associated object.
461
+ # If used along with {belongs_to}[rdoc-ref:Associations::ClassMethods#belongs_to]
462
+ # then +touch+ will invoke +touch+ method on associated object.
437
463
  #
438
464
  # class Brake < ActiveRecord::Base
439
465
  # belongs_to :car, touch: true
@@ -452,26 +478,38 @@ module ActiveRecord
452
478
  # ball = Ball.new
453
479
  # ball.touch(:updated_at) # => raises ActiveRecordError
454
480
  #
455
- def touch(*names)
481
+ def touch(*names, time: nil)
456
482
  raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
457
483
 
484
+ time ||= current_time_from_proper_timezone
458
485
  attributes = timestamp_attributes_for_update_in_model
459
486
  attributes.concat(names)
460
487
 
461
488
  unless attributes.empty?
462
- current_time = current_time_from_proper_timezone
463
489
  changes = {}
464
490
 
465
491
  attributes.each do |column|
466
492
  column = column.to_s
467
- changes[column] = write_attribute(column, current_time)
493
+ changes[column] = write_attribute(column, time)
468
494
  end
469
495
 
470
- changes[self.class.locking_column] = increment_lock if locking_enabled?
471
-
472
496
  clear_attribute_changes(changes.keys)
473
497
  primary_key = self.class.primary_key
474
- self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
498
+ scope = self.class.unscoped.where(primary_key => _read_attribute(primary_key))
499
+
500
+ if locking_enabled?
501
+ locking_column = self.class.locking_column
502
+ scope = scope.where(locking_column => _read_attribute(locking_column))
503
+ changes[locking_column] = increment_lock
504
+ end
505
+
506
+ result = scope.update_all(changes) == 1
507
+
508
+ if !result && locking_enabled?
509
+ raise ActiveRecord::StaleObjectError.new(self, "touch")
510
+ end
511
+
512
+ result
475
513
  else
476
514
  true
477
515
  end
@@ -488,20 +526,12 @@ module ActiveRecord
488
526
  end
489
527
 
490
528
  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
529
+ self.class.unscoped.where(self.class.primary_key => id)
500
530
  end
501
531
 
502
- def create_or_update
532
+ def create_or_update(*args)
503
533
  raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
504
- result = new_record? ? _create_record : _update_record
534
+ result = new_record? ? _create_record : _update_record(*args)
505
535
  result != false
506
536
  end
507
537
 
@@ -531,5 +561,16 @@ module ActiveRecord
531
561
  def verify_readonly_attribute(name)
532
562
  raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
533
563
  end
564
+
565
+ def _raise_record_not_destroyed
566
+ @_association_destroy_exception ||= nil
567
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy the record", self)
568
+ ensure
569
+ @_association_destroy_exception = nil
570
+ end
571
+
572
+ def belongs_to_touch_method
573
+ :touch
574
+ end
534
575
  end
535
576
  end