activerecord 3.2.19 → 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 (264) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1715 -604
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +40 -45
  5. data/examples/performance.rb +33 -22
  6. data/examples/simple.rb +3 -4
  7. data/lib/active_record/aggregations.rb +76 -51
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +54 -40
  10. data/lib/active_record/associations/association.rb +76 -56
  11. data/lib/active_record/associations/association_scope.rb +125 -93
  12. data/lib/active_record/associations/belongs_to_association.rb +57 -28
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +120 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +115 -62
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -53
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
  18. data/lib/active_record/associations/builder/has_many.rb +9 -65
  19. data/lib/active_record/associations/builder/has_one.rb +18 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +18 -19
  21. data/lib/active_record/associations/collection_association.rb +268 -186
  22. data/lib/active_record/associations/collection_proxy.rb +1003 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +81 -41
  25. data/lib/active_record/associations/has_many_through_association.rb +76 -55
  26. data/lib/active_record/associations/has_one_association.rb +51 -21
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +239 -155
  32. data/lib/active_record/associations/preloader/association.rb +97 -62
  33. data/lib/active_record/associations/preloader/collection_association.rb +2 -8
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +75 -33
  38. data/lib/active_record/associations/preloader.rb +111 -79
  39. data/lib/active_record/associations/singular_association.rb +35 -13
  40. data/lib/active_record/associations/through_association.rb +41 -19
  41. data/lib/active_record/associations.rb +727 -501
  42. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  43. data/lib/active_record/attribute.rb +213 -0
  44. data/lib/active_record/attribute_assignment.rb +32 -162
  45. data/lib/active_record/attribute_decorators.rb +67 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  47. data/lib/active_record/attribute_methods/dirty.rb +101 -61
  48. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  49. data/lib/active_record/attribute_methods/query.rb +7 -6
  50. data/lib/active_record/attribute_methods/read.rb +56 -117
  51. data/lib/active_record/attribute_methods/serialization.rb +43 -96
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
  53. data/lib/active_record/attribute_methods/write.rb +34 -45
  54. data/lib/active_record/attribute_methods.rb +333 -144
  55. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  56. data/lib/active_record/attribute_set/builder.rb +108 -0
  57. data/lib/active_record/attribute_set.rb +108 -0
  58. data/lib/active_record/attributes.rb +265 -0
  59. data/lib/active_record/autosave_association.rb +285 -223
  60. data/lib/active_record/base.rb +95 -490
  61. data/lib/active_record/callbacks.rb +95 -61
  62. data/lib/active_record/coders/json.rb +13 -0
  63. data/lib/active_record/coders/yaml_column.rb +28 -19
  64. data/lib/active_record/collection_cache_key.rb +40 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
  78. data/lib/active_record/connection_adapters/column.rb +30 -259
  79. data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
  80. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  81. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  82. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  83. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  84. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  89. data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
  90. data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
  91. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
  92. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
  115. data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
  116. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
  117. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
  118. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  119. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
  120. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  121. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  122. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
  123. data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
  124. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  125. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
  129. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  130. data/lib/active_record/connection_handling.rb +155 -0
  131. data/lib/active_record/core.rb +561 -0
  132. data/lib/active_record/counter_cache.rb +146 -105
  133. data/lib/active_record/dynamic_matchers.rb +101 -64
  134. data/lib/active_record/enum.rb +234 -0
  135. data/lib/active_record/errors.rb +153 -56
  136. data/lib/active_record/explain.rb +15 -63
  137. data/lib/active_record/explain_registry.rb +30 -0
  138. data/lib/active_record/explain_subscriber.rb +10 -6
  139. data/lib/active_record/fixture_set/file.rb +77 -0
  140. data/lib/active_record/fixtures.rb +355 -232
  141. data/lib/active_record/gem_version.rb +15 -0
  142. data/lib/active_record/inheritance.rb +144 -79
  143. data/lib/active_record/integration.rb +66 -13
  144. data/lib/active_record/internal_metadata.rb +56 -0
  145. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  146. data/lib/active_record/locale/en.yml +9 -1
  147. data/lib/active_record/locking/optimistic.rb +77 -56
  148. data/lib/active_record/locking/pessimistic.rb +6 -6
  149. data/lib/active_record/log_subscriber.rb +53 -28
  150. data/lib/active_record/migration/command_recorder.rb +166 -33
  151. data/lib/active_record/migration/compatibility.rb +126 -0
  152. data/lib/active_record/migration/join_table.rb +15 -0
  153. data/lib/active_record/migration.rb +792 -264
  154. data/lib/active_record/model_schema.rb +192 -130
  155. data/lib/active_record/nested_attributes.rb +238 -145
  156. data/lib/active_record/no_touching.rb +52 -0
  157. data/lib/active_record/null_relation.rb +89 -0
  158. data/lib/active_record/persistence.rb +357 -157
  159. data/lib/active_record/query_cache.rb +22 -43
  160. data/lib/active_record/querying.rb +34 -23
  161. data/lib/active_record/railtie.rb +88 -48
  162. data/lib/active_record/railties/console_sandbox.rb +3 -4
  163. data/lib/active_record/railties/controller_runtime.rb +5 -4
  164. data/lib/active_record/railties/databases.rake +170 -422
  165. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  166. data/lib/active_record/readonly_attributes.rb +2 -5
  167. data/lib/active_record/reflection.rb +715 -189
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  169. data/lib/active_record/relation/batches.rb +203 -50
  170. data/lib/active_record/relation/calculations.rb +203 -194
  171. data/lib/active_record/relation/delegation.rb +103 -25
  172. data/lib/active_record/relation/finder_methods.rb +457 -261
  173. data/lib/active_record/relation/from_clause.rb +32 -0
  174. data/lib/active_record/relation/merger.rb +167 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  179. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  180. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  181. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  182. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  183. data/lib/active_record/relation/predicate_builder.rb +153 -48
  184. data/lib/active_record/relation/query_attribute.rb +19 -0
  185. data/lib/active_record/relation/query_methods.rb +1019 -194
  186. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  187. data/lib/active_record/relation/spawn_methods.rb +46 -150
  188. data/lib/active_record/relation/where_clause.rb +174 -0
  189. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  190. data/lib/active_record/relation.rb +450 -245
  191. data/lib/active_record/result.rb +104 -12
  192. data/lib/active_record/runtime_registry.rb +22 -0
  193. data/lib/active_record/sanitization.rb +120 -94
  194. data/lib/active_record/schema.rb +28 -18
  195. data/lib/active_record/schema_dumper.rb +141 -74
  196. data/lib/active_record/schema_migration.rb +50 -0
  197. data/lib/active_record/scoping/default.rb +64 -57
  198. data/lib/active_record/scoping/named.rb +93 -108
  199. data/lib/active_record/scoping.rb +73 -121
  200. data/lib/active_record/secure_token.rb +38 -0
  201. data/lib/active_record/serialization.rb +7 -5
  202. data/lib/active_record/statement_cache.rb +113 -0
  203. data/lib/active_record/store.rb +173 -15
  204. data/lib/active_record/suppressor.rb +58 -0
  205. data/lib/active_record/table_metadata.rb +68 -0
  206. data/lib/active_record/tasks/database_tasks.rb +313 -0
  207. data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
  208. data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
  209. data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
  210. data/lib/active_record/timestamp.rb +42 -24
  211. data/lib/active_record/touch_later.rb +58 -0
  212. data/lib/active_record/transactions.rb +233 -105
  213. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  214. data/lib/active_record/type/date.rb +7 -0
  215. data/lib/active_record/type/date_time.rb +7 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  217. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  218. data/lib/active_record/type/internal/timezone.rb +15 -0
  219. data/lib/active_record/type/serialized.rb +63 -0
  220. data/lib/active_record/type/time.rb +20 -0
  221. data/lib/active_record/type/type_map.rb +64 -0
  222. data/lib/active_record/type.rb +72 -0
  223. data/lib/active_record/type_caster/connection.rb +29 -0
  224. data/lib/active_record/type_caster/map.rb +19 -0
  225. data/lib/active_record/type_caster.rb +7 -0
  226. data/lib/active_record/validations/absence.rb +23 -0
  227. data/lib/active_record/validations/associated.rb +33 -18
  228. data/lib/active_record/validations/length.rb +24 -0
  229. data/lib/active_record/validations/presence.rb +66 -0
  230. data/lib/active_record/validations/uniqueness.rb +128 -68
  231. data/lib/active_record/validations.rb +48 -40
  232. data/lib/active_record/version.rb +5 -7
  233. data/lib/active_record.rb +71 -47
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
  235. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
  236. data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
  237. data/lib/rails/generators/active_record/migration.rb +18 -8
  238. data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
  239. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  240. data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
  241. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  242. data/lib/rails/generators/active_record.rb +3 -11
  243. metadata +188 -134
  244. data/examples/associations.png +0 -0
  245. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  246. data/lib/active_record/associations/join_helper.rb +0 -55
  247. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  248. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  249. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  250. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  251. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  252. data/lib/active_record/dynamic_finder_match.rb +0 -68
  253. data/lib/active_record/dynamic_scope_match.rb +0 -23
  254. data/lib/active_record/fixtures/file.rb +0 -65
  255. data/lib/active_record/identity_map.rb +0 -162
  256. data/lib/active_record/observer.rb +0 -121
  257. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  258. data/lib/active_record/session_store.rb +0 -360
  259. data/lib/active_record/test_case.rb +0 -73
  260. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  261. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  262. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  263. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  264. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,13 +1,11 @@
1
- require 'active_support/core_ext/array/wrap'
2
-
3
1
  module ActiveRecord
4
- # = Active Record Callbacks
2
+ # = Active Record \Callbacks
5
3
  #
6
- # Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
4
+ # \Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
7
5
  # before or after an alteration of the object state. This can be used to make sure that associated and
8
- # dependent objects are deleted when +destroy+ is called (by overwriting +before_destroy+) or to massage attributes
9
- # before they're validated (by overwriting +before_validation+). As an example of the callbacks initiated, consider
10
- # the <tt>Base#save</tt> call for a new record:
6
+ # dependent objects are deleted when {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] is called (by overwriting +before_destroy+) or
7
+ # to massage attributes before they're validated (by overwriting +before_validation+).
8
+ # As an example of the callbacks initiated, consider the {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] call for a new record:
11
9
  #
12
10
  # * (-) <tt>save</tt>
13
11
  # * (-) <tt>valid</tt>
@@ -22,22 +20,25 @@ module ActiveRecord
22
20
  # * (7) <tt>after_commit</tt>
23
21
  #
24
22
  # Also, an <tt>after_rollback</tt> callback can be configured to be triggered whenever a rollback is issued.
25
- # Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
23
+ # Check out ActiveRecord::Transactions for more details about <tt>after_commit</tt> and
26
24
  # <tt>after_rollback</tt>.
27
25
  #
28
- # Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
26
+ # Additionally, an <tt>after_touch</tt> callback is triggered whenever an
27
+ # object is touched.
28
+ #
29
+ # Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
29
30
  # is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
30
31
  # are instantiated as well.
31
32
  #
32
- # That's a total of twelve callbacks, which gives you immense power to react and prepare for each state in the
33
- # Active Record life cycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar,
33
+ # There are nineteen callbacks in total, which give you immense power to react and prepare for each state in the
34
+ # Active Record life cycle. The sequence for calling {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] for an existing record is similar,
34
35
  # except that each <tt>_create</tt> callback is replaced by the corresponding <tt>_update</tt> callback.
35
36
  #
36
37
  # Examples:
37
38
  # class CreditCard < ActiveRecord::Base
38
39
  # # Strip everything but digits, so the user can specify "555 234 34" or
39
- # # "5552-3434" or both will mean "55523434"
40
- # before_validation(:on => :create) do
40
+ # # "5552-3434" and both will mean "55523434"
41
+ # before_validation(on: :create) do
41
42
  # self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
42
43
  # end
43
44
  # end
@@ -52,9 +53,9 @@ module ActiveRecord
52
53
  # end
53
54
  #
54
55
  # class Firm < ActiveRecord::Base
55
- # # Destroys the associated clients and people when the firm is destroyed
56
- # before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
57
- # before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
56
+ # # Disables access to the system, for associated clients and people when the firm is destroyed
57
+ # before_destroy { |record| Person.where(firm_id: record.id).update_all(access: 'disabled') }
58
+ # before_destroy { |record| Client.where(client_of: record.id).update_all(access: 'disabled') }
58
59
  # end
59
60
  #
60
61
  # == Inheritable callback queues
@@ -85,7 +86,7 @@ module ActiveRecord
85
86
  #
86
87
  # In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
87
88
  # So, use the callback macros when you want to ensure that a certain callback is called for the entire
88
- # hierarchy, and use the regular overwriteable methods when you want to leave it up to each descendant
89
+ # hierarchy, and use the regular overwritable methods when you want to leave it up to each descendant
89
90
  # to decide whether they want to call +super+ and trigger the inherited callbacks.
90
91
  #
91
92
  # *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
@@ -127,7 +128,7 @@ module ActiveRecord
127
128
  # record.credit_card_number = decrypt(record.credit_card_number)
128
129
  # end
129
130
  #
130
- # alias_method :after_find, :after_save
131
+ # alias_method :after_initialize, :after_save
131
132
  #
132
133
  # private
133
134
  # def encrypt(value)
@@ -162,7 +163,7 @@ module ActiveRecord
162
163
  # record.send("#{@attribute}=", decrypt(record.send("#{@attribute}")))
163
164
  # end
164
165
  #
165
- # alias_method :after_find, :after_save
166
+ # alias_method :after_initialize, :after_save
166
167
  #
167
168
  # private
168
169
  # def encrypt(value)
@@ -174,64 +175,86 @@ module ActiveRecord
174
175
  # end
175
176
  # end
176
177
  #
177
- # The callback macros usually accept a symbol for the method they're supposed to run, but you can also
178
- # pass a "method string", which will then be evaluated within the binding of the callback. Example:
178
+ # == <tt>before_validation*</tt> returning statements
179
179
  #
180
- # class Topic < ActiveRecord::Base
181
- # before_destroy 'self.class.delete_all "parent_id = #{id}"'
182
- # end
180
+ # If the +before_validation+ callback throws +:abort+, the process will be
181
+ # aborted and {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] will return +false+.
182
+ # If {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] is called it will raise an ActiveRecord::RecordInvalid exception.
183
+ # Nothing will be appended to the errors object.
184
+ #
185
+ # == Canceling callbacks
186
+ #
187
+ # If a <tt>before_*</tt> callback throws +:abort+, all the later callbacks and
188
+ # the associated action are cancelled.
189
+ # Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
190
+ # methods on the model, which are called last.
191
+ #
192
+ # == Ordering callbacks
193
+ #
194
+ # Sometimes the code needs that the callbacks execute in a specific order. For example, a +before_destroy+
195
+ # callback (+log_children+ in this case) should be executed before the children get destroyed by the
196
+ # <tt>dependent: :destroy</tt> option.
183
197
  #
184
- # Notice that single quotes (') are used so the <tt>#{id}</tt> part isn't evaluated until the callback
185
- # is triggered. Also note that these inline callbacks can be stacked just like the regular ones:
198
+ # Let's look at the code below:
186
199
  #
187
200
  # class Topic < ActiveRecord::Base
188
- # before_destroy 'self.class.delete_all "parent_id = #{id}"',
189
- # 'puts "Evaluated after parents are destroyed"'
201
+ # has_many :children, dependent: :destroy
202
+ #
203
+ # before_destroy :log_children
204
+ #
205
+ # private
206
+ # def log_children
207
+ # # Child processing
208
+ # end
190
209
  # end
191
210
  #
192
- # == <tt>before_validation*</tt> returning statements
211
+ # In this case, the problem is that when the +before_destroy+ callback is executed, the children are not available
212
+ # because the {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] callback gets executed first.
213
+ # You can use the +prepend+ option on the +before_destroy+ callback to avoid this.
193
214
  #
194
- # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be
195
- # aborted and <tt>Base#save</tt> will return +false+. If Base#save! is called it will raise a
196
- # ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object.
215
+ # class Topic < ActiveRecord::Base
216
+ # has_many :children, dependent: :destroy
197
217
  #
198
- # == Canceling callbacks
218
+ # before_destroy :log_children, prepend: true
199
219
  #
200
- # If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are
201
- # cancelled. If an <tt>after_*</tt> callback returns +false+, all the later callbacks are cancelled.
202
- # Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
203
- # methods on the model, which are called last.
220
+ # private
221
+ # def log_children
222
+ # # Child processing
223
+ # end
224
+ # end
225
+ #
226
+ # This way, the +before_destroy+ gets executed before the <tt>dependent: :destroy</tt> is called, and the data is still available.
204
227
  #
205
- # == Transactions
228
+ # == \Transactions
206
229
  #
207
- # The entire callback chain of a +save+, <tt>save!</tt>, or +destroy+ call runs
208
- # within a transaction. That includes <tt>after_*</tt> hooks. If everything
209
- # goes fine a COMMIT is executed once the chain has been completed.
230
+ # The entire callback chain of a {#save}[rdoc-ref:Persistence#save], {#save!}[rdoc-ref:Persistence#save!],
231
+ # or {#destroy}[rdoc-ref:Persistence#destroy] call runs within a transaction. That includes <tt>after_*</tt> hooks.
232
+ # If everything goes fine a COMMIT is executed once the chain has been completed.
210
233
  #
211
234
  # If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
212
235
  # can also trigger a ROLLBACK raising an exception in any of the callbacks,
213
236
  # including <tt>after_*</tt> hooks. Note, however, that in that case the client
214
- # needs to be aware of it because an ordinary +save+ will raise such exception
237
+ # needs to be aware of it because an ordinary {#save}[rdoc-ref:Persistence#save] will raise such exception
215
238
  # instead of quietly returning +false+.
216
239
  #
217
240
  # == Debugging callbacks
218
- #
219
- # The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object. ActiveModel Callbacks support
241
+ #
242
+ # The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object. Active Model \Callbacks support
220
243
  # <tt>:before</tt>, <tt>:after</tt> and <tt>:around</tt> as values for the <tt>kind</tt> property. The <tt>kind</tt> property
221
244
  # defines what part of the chain the callback runs in.
222
- #
223
- # To find all callbacks in the before_save callback chain:
224
- #
245
+ #
246
+ # To find all callbacks in the before_save callback chain:
247
+ #
225
248
  # Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
226
- #
249
+ #
227
250
  # Returns an array of callback objects that form the before_save chain.
228
- #
251
+ #
229
252
  # To further check if the before_save chain contains a proc defined as <tt>rest_when_dead</tt> use the <tt>filter</tt> property of the callback object:
230
- #
253
+ #
231
254
  # Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:rest_when_dead)
232
- #
255
+ #
233
256
  # Returns true or false depending on whether the proc is contained in the before_save callback chain on a Topic model.
234
- #
257
+ #
235
258
  module Callbacks
236
259
  extend ActiveSupport::Concern
237
260
 
@@ -242,8 +265,11 @@ module ActiveRecord
242
265
  :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
243
266
  ]
244
267
 
268
+ module ClassMethods # :nodoc:
269
+ include ActiveModel::Callbacks
270
+ end
271
+
245
272
  included do
246
- extend ActiveModel::Callbacks
247
273
  include ActiveModel::Validations::Callbacks
248
274
 
249
275
  define_model_callbacks :initialize, :find, :touch, :only => :after
@@ -251,25 +277,33 @@ module ActiveRecord
251
277
  end
252
278
 
253
279
  def destroy #:nodoc:
254
- run_callbacks(:destroy) { super }
280
+ @_destroy_callback_already_called ||= false
281
+ return if @_destroy_callback_already_called
282
+ @_destroy_callback_already_called = true
283
+ _run_destroy_callbacks { super }
284
+ rescue RecordNotDestroyed => e
285
+ @_association_destroy_exception = e
286
+ false
287
+ ensure
288
+ @_destroy_callback_already_called = false
255
289
  end
256
290
 
257
291
  def touch(*) #:nodoc:
258
- run_callbacks(:touch) { super }
292
+ _run_touch_callbacks { super }
259
293
  end
260
294
 
261
295
  private
262
296
 
263
- def create_or_update #:nodoc:
264
- run_callbacks(:save) { super }
297
+ def create_or_update(*) #:nodoc:
298
+ _run_save_callbacks { super }
265
299
  end
266
300
 
267
- def create #:nodoc:
268
- run_callbacks(:create) { super }
301
+ def _create_record #:nodoc:
302
+ _run_create_callbacks { super }
269
303
  end
270
304
 
271
- def update(*) #:nodoc:
272
- run_callbacks(:update) { super }
305
+ def _update_record(*) #:nodoc:
306
+ _run_update_callbacks { super }
273
307
  end
274
308
  end
275
309
  end
@@ -0,0 +1,13 @@
1
+ module ActiveRecord
2
+ module Coders # :nodoc:
3
+ class JSON # :nodoc:
4
+ def self.dump(obj)
5
+ ActiveSupport::JSON.encode(obj)
6
+ end
7
+
8
+ def self.load(json)
9
+ ActiveSupport::JSON.decode(json) unless json.blank?
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,41 +1,50 @@
1
- module ActiveRecord
2
- # :stopdoc:
3
- module Coders
4
- class YAMLColumn
5
- RESCUE_ERRORS = [ ArgumentError ]
1
+ require 'yaml'
6
2
 
7
- if defined?(Psych) && defined?(Psych::SyntaxError)
8
- RESCUE_ERRORS << Psych::SyntaxError
9
- end
3
+ module ActiveRecord
4
+ module Coders # :nodoc:
5
+ class YAMLColumn # :nodoc:
10
6
 
11
7
  attr_accessor :object_class
12
8
 
13
9
  def initialize(object_class = Object)
14
10
  @object_class = object_class
11
+ check_arity_of_constructor
15
12
  end
16
13
 
17
14
  def dump(obj)
15
+ return if obj.nil?
16
+
17
+ assert_valid_value(obj)
18
18
  YAML.dump obj
19
19
  end
20
20
 
21
21
  def load(yaml)
22
22
  return object_class.new if object_class != Object && yaml.nil?
23
23
  return yaml unless yaml.is_a?(String) && yaml =~ /^---/
24
- begin
25
- obj = YAML.load(yaml)
24
+ obj = YAML.load(yaml)
25
+
26
+ assert_valid_value(obj)
27
+ obj ||= object_class.new if object_class != Object
26
28
 
27
- unless obj.is_a?(object_class) || obj.nil?
28
- raise SerializationTypeMismatch,
29
- "Attribute was supposed to be a #{object_class}, but was a #{obj.class}"
30
- end
31
- obj ||= object_class.new if object_class != Object
29
+ obj
30
+ end
31
+
32
+ def assert_valid_value(obj)
33
+ unless obj.nil? || obj.is_a?(object_class)
34
+ raise SerializationTypeMismatch,
35
+ "Attribute was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
36
+ end
37
+ end
38
+
39
+ private
32
40
 
33
- obj
34
- rescue *RESCUE_ERRORS
35
- yaml
41
+ def check_arity_of_constructor
42
+ begin
43
+ load(nil)
44
+ rescue ArgumentError
45
+ raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
36
46
  end
37
47
  end
38
48
  end
39
49
  end
40
- # :startdoc
41
50
  end
@@ -0,0 +1,40 @@
1
+ module ActiveRecord
2
+ module CollectionCacheKey
3
+
4
+ def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
5
+ query_signature = Digest::MD5.hexdigest(collection.to_sql)
6
+ key = "#{collection.model_name.cache_key}/query-#{query_signature}"
7
+
8
+ if collection.loaded?
9
+ size = collection.size
10
+ if size > 0
11
+ timestamp = collection.max_by(&timestamp_column).public_send(timestamp_column)
12
+ end
13
+ else
14
+ column_type = type_for_attribute(timestamp_column.to_s)
15
+ column = "#{connection.quote_table_name(collection.table_name)}.#{connection.quote_column_name(timestamp_column)}"
16
+
17
+ query = collection
18
+ .unscope(:select)
19
+ .select("COUNT(*) AS #{connection.quote_column_name("size")}", "MAX(#{column}) AS timestamp")
20
+ .unscope(:order)
21
+ result = connection.select_one(query)
22
+
23
+ if result.blank?
24
+ size = 0
25
+ timestamp = nil
26
+ else
27
+ size = result["size"]
28
+ timestamp = column_type.deserialize(result["timestamp"])
29
+ end
30
+
31
+ end
32
+
33
+ if timestamp
34
+ "#{key}-#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}"
35
+ else
36
+ "#{key}-#{size}"
37
+ end
38
+ end
39
+ end
40
+ end