activerecord 1.0.0 → 4.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 (255) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2102 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +213 -0
  5. data/examples/performance.rb +172 -0
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record/aggregations.rb +180 -84
  8. data/lib/active_record/associations/alias_tracker.rb +76 -0
  9. data/lib/active_record/associations/association.rb +248 -0
  10. data/lib/active_record/associations/association_scope.rb +135 -0
  11. data/lib/active_record/associations/belongs_to_association.rb +92 -0
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +35 -0
  13. data/lib/active_record/associations/builder/association.rb +108 -0
  14. data/lib/active_record/associations/builder/belongs_to.rb +98 -0
  15. data/lib/active_record/associations/builder/collection_association.rb +89 -0
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
  17. data/lib/active_record/associations/builder/has_many.rb +15 -0
  18. data/lib/active_record/associations/builder/has_one.rb +25 -0
  19. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  20. data/lib/active_record/associations/collection_association.rb +608 -0
  21. data/lib/active_record/associations/collection_proxy.rb +986 -0
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +58 -39
  23. data/lib/active_record/associations/has_many_association.rb +116 -85
  24. data/lib/active_record/associations/has_many_through_association.rb +197 -0
  25. data/lib/active_record/associations/has_one_association.rb +102 -0
  26. data/lib/active_record/associations/has_one_through_association.rb +36 -0
  27. data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_dependency.rb +235 -0
  31. data/lib/active_record/associations/join_helper.rb +45 -0
  32. data/lib/active_record/associations/preloader/association.rb +121 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +63 -0
  42. data/lib/active_record/associations/preloader.rb +178 -0
  43. data/lib/active_record/associations/singular_association.rb +64 -0
  44. data/lib/active_record/associations/through_association.rb +87 -0
  45. data/lib/active_record/associations.rb +1437 -431
  46. data/lib/active_record/attribute_assignment.rb +201 -0
  47. data/lib/active_record/attribute_methods/before_type_cast.rb +70 -0
  48. data/lib/active_record/attribute_methods/dirty.rb +118 -0
  49. data/lib/active_record/attribute_methods/primary_key.rb +122 -0
  50. data/lib/active_record/attribute_methods/query.rb +40 -0
  51. data/lib/active_record/attribute_methods/read.rb +107 -0
  52. data/lib/active_record/attribute_methods/serialization.rb +162 -0
  53. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -0
  54. data/lib/active_record/attribute_methods/write.rb +63 -0
  55. data/lib/active_record/attribute_methods.rb +393 -0
  56. data/lib/active_record/autosave_association.rb +426 -0
  57. data/lib/active_record/base.rb +268 -930
  58. data/lib/active_record/callbacks.rb +203 -230
  59. data/lib/active_record/coders/yaml_column.rb +38 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +638 -0
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +390 -0
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +129 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +501 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +873 -0
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +389 -275
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
  71. data/lib/active_record/connection_adapters/column.rb +318 -0
  72. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  73. data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
  74. data/lib/active_record/connection_adapters/mysql_adapter.rb +517 -90
  75. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
  76. data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
  77. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
  79. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
  80. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  81. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
  82. data/lib/active_record/connection_adapters/postgresql_adapter.rb +911 -138
  83. data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
  84. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +624 -0
  85. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  86. data/lib/active_record/connection_handling.rb +98 -0
  87. data/lib/active_record/core.rb +463 -0
  88. data/lib/active_record/counter_cache.rb +122 -0
  89. data/lib/active_record/dynamic_matchers.rb +131 -0
  90. data/lib/active_record/errors.rb +213 -0
  91. data/lib/active_record/explain.rb +38 -0
  92. data/lib/active_record/explain_registry.rb +30 -0
  93. data/lib/active_record/explain_subscriber.rb +29 -0
  94. data/lib/active_record/fixture_set/file.rb +55 -0
  95. data/lib/active_record/fixtures.rb +892 -138
  96. data/lib/active_record/inheritance.rb +200 -0
  97. data/lib/active_record/integration.rb +60 -0
  98. data/lib/active_record/locale/en.yml +47 -0
  99. data/lib/active_record/locking/optimistic.rb +181 -0
  100. data/lib/active_record/locking/pessimistic.rb +77 -0
  101. data/lib/active_record/log_subscriber.rb +82 -0
  102. data/lib/active_record/migration/command_recorder.rb +164 -0
  103. data/lib/active_record/migration/join_table.rb +15 -0
  104. data/lib/active_record/migration.rb +1015 -0
  105. data/lib/active_record/model_schema.rb +345 -0
  106. data/lib/active_record/nested_attributes.rb +546 -0
  107. data/lib/active_record/null_relation.rb +65 -0
  108. data/lib/active_record/persistence.rb +509 -0
  109. data/lib/active_record/query_cache.rb +56 -0
  110. data/lib/active_record/querying.rb +62 -0
  111. data/lib/active_record/railtie.rb +205 -0
  112. data/lib/active_record/railties/console_sandbox.rb +5 -0
  113. data/lib/active_record/railties/controller_runtime.rb +50 -0
  114. data/lib/active_record/railties/databases.rake +402 -0
  115. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  116. data/lib/active_record/readonly_attributes.rb +30 -0
  117. data/lib/active_record/reflection.rb +544 -87
  118. data/lib/active_record/relation/batches.rb +93 -0
  119. data/lib/active_record/relation/calculations.rb +399 -0
  120. data/lib/active_record/relation/delegation.rb +125 -0
  121. data/lib/active_record/relation/finder_methods.rb +349 -0
  122. data/lib/active_record/relation/merger.rb +161 -0
  123. data/lib/active_record/relation/predicate_builder.rb +106 -0
  124. data/lib/active_record/relation/query_methods.rb +1044 -0
  125. data/lib/active_record/relation/spawn_methods.rb +73 -0
  126. data/lib/active_record/relation.rb +655 -0
  127. data/lib/active_record/result.rb +67 -0
  128. data/lib/active_record/runtime_registry.rb +17 -0
  129. data/lib/active_record/sanitization.rb +168 -0
  130. data/lib/active_record/schema.rb +65 -0
  131. data/lib/active_record/schema_dumper.rb +204 -0
  132. data/lib/active_record/schema_migration.rb +39 -0
  133. data/lib/active_record/scoping/default.rb +146 -0
  134. data/lib/active_record/scoping/named.rb +175 -0
  135. data/lib/active_record/scoping.rb +82 -0
  136. data/lib/active_record/serialization.rb +22 -0
  137. data/lib/active_record/serializers/xml_serializer.rb +197 -0
  138. data/lib/active_record/statement_cache.rb +26 -0
  139. data/lib/active_record/store.rb +156 -0
  140. data/lib/active_record/tasks/database_tasks.rb +203 -0
  141. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  142. data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
  143. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  144. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  145. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  146. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  147. data/lib/active_record/test_case.rb +96 -0
  148. data/lib/active_record/timestamp.rb +119 -0
  149. data/lib/active_record/transactions.rb +366 -69
  150. data/lib/active_record/translation.rb +22 -0
  151. data/lib/active_record/validations/associated.rb +49 -0
  152. data/lib/active_record/validations/presence.rb +65 -0
  153. data/lib/active_record/validations/uniqueness.rb +225 -0
  154. data/lib/active_record/validations.rb +64 -185
  155. data/lib/active_record/version.rb +11 -0
  156. data/lib/active_record.rb +149 -24
  157. data/lib/rails/generators/active_record/migration/migration_generator.rb +62 -0
  158. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  159. data/lib/rails/generators/active_record/migration/templates/migration.rb +39 -0
  160. data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
  161. data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
  162. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  163. data/lib/rails/generators/active_record.rb +23 -0
  164. metadata +261 -161
  165. data/CHANGELOG +0 -581
  166. data/README +0 -361
  167. data/RUNNING_UNIT_TESTS +0 -36
  168. data/dev-utils/eval_debugger.rb +0 -9
  169. data/examples/associations.png +0 -0
  170. data/examples/associations.rb +0 -87
  171. data/examples/shared_setup.rb +0 -15
  172. data/examples/validation.rb +0 -88
  173. data/install.rb +0 -60
  174. data/lib/active_record/associations/association_collection.rb +0 -70
  175. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -107
  176. data/lib/active_record/deprecated_associations.rb +0 -70
  177. data/lib/active_record/observer.rb +0 -71
  178. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  179. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  180. data/lib/active_record/support/clean_logger.rb +0 -10
  181. data/lib/active_record/support/inflector.rb +0 -70
  182. data/lib/active_record/vendor/mysql.rb +0 -1117
  183. data/lib/active_record/vendor/simple.rb +0 -702
  184. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  185. data/lib/active_record/wrappings.rb +0 -59
  186. data/rakefile +0 -122
  187. data/test/abstract_unit.rb +0 -16
  188. data/test/aggregations_test.rb +0 -34
  189. data/test/all.sh +0 -8
  190. data/test/associations_test.rb +0 -477
  191. data/test/base_test.rb +0 -513
  192. data/test/class_inheritable_attributes_test.rb +0 -33
  193. data/test/connections/native_mysql/connection.rb +0 -24
  194. data/test/connections/native_postgresql/connection.rb +0 -24
  195. data/test/connections/native_sqlite/connection.rb +0 -24
  196. data/test/deprecated_associations_test.rb +0 -336
  197. data/test/finder_test.rb +0 -67
  198. data/test/fixtures/accounts/signals37 +0 -3
  199. data/test/fixtures/accounts/unknown +0 -2
  200. data/test/fixtures/auto_id.rb +0 -4
  201. data/test/fixtures/column_name.rb +0 -3
  202. data/test/fixtures/companies/first_client +0 -6
  203. data/test/fixtures/companies/first_firm +0 -4
  204. data/test/fixtures/companies/second_client +0 -6
  205. data/test/fixtures/company.rb +0 -37
  206. data/test/fixtures/company_in_module.rb +0 -33
  207. data/test/fixtures/course.rb +0 -3
  208. data/test/fixtures/courses/java +0 -2
  209. data/test/fixtures/courses/ruby +0 -2
  210. data/test/fixtures/customer.rb +0 -30
  211. data/test/fixtures/customers/david +0 -6
  212. data/test/fixtures/db_definitions/mysql.sql +0 -96
  213. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  214. data/test/fixtures/db_definitions/postgresql.sql +0 -113
  215. data/test/fixtures/db_definitions/postgresql2.sql +0 -4
  216. data/test/fixtures/db_definitions/sqlite.sql +0 -85
  217. data/test/fixtures/db_definitions/sqlite2.sql +0 -4
  218. data/test/fixtures/default.rb +0 -2
  219. data/test/fixtures/developer.rb +0 -8
  220. data/test/fixtures/developers/david +0 -2
  221. data/test/fixtures/developers/jamis +0 -2
  222. data/test/fixtures/developers_projects/david_action_controller +0 -2
  223. data/test/fixtures/developers_projects/david_active_record +0 -2
  224. data/test/fixtures/developers_projects/jamis_active_record +0 -2
  225. data/test/fixtures/entrant.rb +0 -3
  226. data/test/fixtures/entrants/first +0 -3
  227. data/test/fixtures/entrants/second +0 -3
  228. data/test/fixtures/entrants/third +0 -3
  229. data/test/fixtures/fixture_database.sqlite +0 -0
  230. data/test/fixtures/fixture_database_2.sqlite +0 -0
  231. data/test/fixtures/movie.rb +0 -5
  232. data/test/fixtures/movies/first +0 -2
  233. data/test/fixtures/movies/second +0 -2
  234. data/test/fixtures/project.rb +0 -3
  235. data/test/fixtures/projects/action_controller +0 -2
  236. data/test/fixtures/projects/active_record +0 -2
  237. data/test/fixtures/reply.rb +0 -21
  238. data/test/fixtures/subscriber.rb +0 -5
  239. data/test/fixtures/subscribers/first +0 -2
  240. data/test/fixtures/subscribers/second +0 -2
  241. data/test/fixtures/topic.rb +0 -20
  242. data/test/fixtures/topics/first +0 -9
  243. data/test/fixtures/topics/second +0 -8
  244. data/test/fixtures_test.rb +0 -20
  245. data/test/inflector_test.rb +0 -104
  246. data/test/inheritance_test.rb +0 -125
  247. data/test/lifecycle_test.rb +0 -110
  248. data/test/modules_test.rb +0 -21
  249. data/test/multiple_db_test.rb +0 -46
  250. data/test/pk_test.rb +0 -57
  251. data/test/reflection_test.rb +0 -78
  252. data/test/thread_safety_test.rb +0 -33
  253. data/test/transactions_test.rb +0 -83
  254. data/test/unconnected_test.rb +0 -24
  255. data/test/validations_test.rb +0 -126
@@ -1,57 +1,65 @@
1
- require 'observer'
2
-
3
1
  module ActiveRecord
4
- # Callbacks are hooks into the lifecycle of an Active Record object that allows you to trigger logic
5
- # before or after an alteration of the object state. This can be used to make sure that associated and
6
- # dependent objects are deleted when destroy is called (by overwriting before_destroy) or to massage attributes
7
- # before they're validated (by overwriting before_validation). As an example of the callbacks initiated, consider
8
- # the Base#save call:
9
- #
10
- # * (-) save
11
- # * (-) valid?
12
- # * (1) before_validation
13
- # * (2) before_validation_on_create
14
- # * (-) validate
15
- # * (-) validate_on_create
16
- # * (4) after_validation
17
- # * (5) after_validation_on_create
18
- # * (6) before_save
19
- # * (7) before_create
20
- # * (-) create
21
- # * (8) after_create
22
- # * (9) after_save
23
- #
24
- # That's a total of nine callbacks, which gives you immense power to react and prepare for each state in the
25
- # Active Record lifecyle.
2
+ # = Active Record Callbacks
3
+ #
4
+ # Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
5
+ # before or after an alteration of the object state. This can be used to make sure that associated and
6
+ # dependent objects are deleted when +destroy+ is called (by overwriting +before_destroy+) or to massage attributes
7
+ # before they're validated (by overwriting +before_validation+). As an example of the callbacks initiated, consider
8
+ # the <tt>Base#save</tt> call for a new record:
9
+ #
10
+ # * (-) <tt>save</tt>
11
+ # * (-) <tt>valid</tt>
12
+ # * (1) <tt>before_validation</tt>
13
+ # * (-) <tt>validate</tt>
14
+ # * (2) <tt>after_validation</tt>
15
+ # * (3) <tt>before_save</tt>
16
+ # * (4) <tt>before_create</tt>
17
+ # * (-) <tt>create</tt>
18
+ # * (5) <tt>after_create</tt>
19
+ # * (6) <tt>after_save</tt>
20
+ # * (7) <tt>after_commit</tt>
21
+ #
22
+ # Also, an <tt>after_rollback</tt> callback can be configured to be triggered whenever a rollback is issued.
23
+ # Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
24
+ # <tt>after_rollback</tt>.
25
+ #
26
+ # Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
27
+ # is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
28
+ # are instantiated as well.
29
+ #
30
+ # That's a total of twelve callbacks, which gives you immense power to react and prepare for each state in the
31
+ # Active Record life cycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar,
32
+ # except that each <tt>_create</tt> callback is replaced by the corresponding <tt>_update</tt> callback.
26
33
  #
27
34
  # Examples:
28
35
  # class CreditCard < ActiveRecord::Base
29
- # # Strip everything but digits, so the user can specify "555 234 34" or
30
- # # "5552-3434" or both will mean "55523434"
31
- # def before_validation_on_create
36
+ # # Strip everything but digits, so the user can specify "555 234 34" or
37
+ # # "5552-3434" and both will mean "55523434"
38
+ # before_validation(on: :create) do
32
39
  # self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
33
40
  # end
34
41
  # end
35
42
  #
36
43
  # class Subscription < ActiveRecord::Base
37
- # # Automatically assign the signup date
38
- # def before_create
39
- # self.signed_up_on = Date.today
40
- # end
44
+ # before_create :record_signup
45
+ #
46
+ # private
47
+ # def record_signup
48
+ # self.signed_up_on = Date.today
49
+ # end
41
50
  # end
42
51
  #
43
52
  # class Firm < ActiveRecord::Base
44
53
  # # Destroys the associated clients and people when the firm is destroyed
45
- # def before_destroy
46
- # Client.destroy_all "client_of = #{id}"
47
- # Person.destroy_all "firm_id = #{id}"
48
- # end
54
+ # before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
55
+ # before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
56
+ # end
49
57
  #
50
58
  # == Inheritable callback queues
51
59
  #
52
- # Besides the overwriteable callback methods, it's also possible to register callbacks through the use of the callback macros.
53
- # Their main advantage is that the macros add behavior into a callback queue that is kept intact down through an inheritance
54
- # hierarchy. Example:
60
+ # Besides the overwritable callback methods, it's also possible to register callbacks through the
61
+ # use of the callback macros. Their main advantage is that the macros add behavior into a callback
62
+ # queue that is kept intact down through an inheritance hierarchy.
55
63
  #
56
64
  # class Topic < ActiveRecord::Base
57
65
  # before_destroy :destroy_author
@@ -61,9 +69,9 @@ module ActiveRecord
61
69
  # before_destroy :destroy_readers
62
70
  # end
63
71
  #
64
- # Now, when Topic#destroy is run only +destroy_author+ is called. When Reply#destroy is run both +destroy_author+ and
65
- # +destroy_readers+ is called. Contrast this to the situation where we've implemented the save behavior through overwriteable
66
- # methods:
72
+ # Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is
73
+ # run, both +destroy_author+ and +destroy_readers+ are called. Contrast this to the following situation
74
+ # where the +before_destroy+ method is overridden:
67
75
  #
68
76
  # class Topic < ActiveRecord::Base
69
77
  # def before_destroy() destroy_author end
@@ -73,16 +81,21 @@ module ActiveRecord
73
81
  # def before_destroy() destroy_readers end
74
82
  # end
75
83
  #
76
- # In that case, Reply#destroy would only run +destroy_readers+ and _not_ +destroy_author+. So use the callback macros when
77
- # you want to ensure that a certain callback is called for the entire hierarchy and the regular overwriteable methods when you
78
- # want to leave it up to each descendent to decide whether they want to call +super+ and trigger the inherited callbacks.
84
+ # In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
85
+ # So, use the callback macros when you want to ensure that a certain callback is called for the entire
86
+ # hierarchy, and use the regular overwritable methods when you want to leave it up to each descendant
87
+ # to decide whether they want to call +super+ and trigger the inherited callbacks.
88
+ #
89
+ # *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
90
+ # callbacks before specifying the associations. Otherwise, you might trigger the loading of a
91
+ # child before the parent has registered the callbacks and they won't be inherited.
79
92
  #
80
93
  # == Types of callbacks
81
94
  #
82
- # There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
83
- # inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects are the
84
- # recommended approaches, inline methods using a proc is some times appropriate (such as for creating mix-ins), and inline
85
- # eval methods are deprecated.
95
+ # There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
96
+ # inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects
97
+ # are the recommended approaches, inline methods using a proc are sometimes appropriate (such as for
98
+ # creating mix-ins), and inline eval methods are deprecated.
86
99
  #
87
100
  # The method reference callbacks work by specifying a protected or private method available in the object, like this:
88
101
  #
@@ -98,6 +111,37 @@ module ActiveRecord
98
111
  # The callback objects have methods named after the callback called with the record as the only parameter, such as:
99
112
  #
100
113
  # class BankAccount < ActiveRecord::Base
114
+ # before_save EncryptionWrapper.new
115
+ # after_save EncryptionWrapper.new
116
+ # after_initialize EncryptionWrapper.new
117
+ # end
118
+ #
119
+ # class EncryptionWrapper
120
+ # def before_save(record)
121
+ # record.credit_card_number = encrypt(record.credit_card_number)
122
+ # end
123
+ #
124
+ # def after_save(record)
125
+ # record.credit_card_number = decrypt(record.credit_card_number)
126
+ # end
127
+ #
128
+ # alias_method :after_find, :after_save
129
+ #
130
+ # private
131
+ # def encrypt(value)
132
+ # # Secrecy is committed
133
+ # end
134
+ #
135
+ # def decrypt(value)
136
+ # # Secrecy is unveiled
137
+ # end
138
+ # end
139
+ #
140
+ # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
141
+ # a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other
142
+ # initialization data such as the name of the attribute to work with:
143
+ #
144
+ # class BankAccount < ActiveRecord::Base
101
145
  # before_save EncryptionWrapper.new("credit_card_number")
102
146
  # after_save EncryptionWrapper.new("credit_card_number")
103
147
  # after_initialize EncryptionWrapper.new("credit_card_number")
@@ -109,14 +153,14 @@ module ActiveRecord
109
153
  # end
110
154
  #
111
155
  # def before_save(record)
112
- # record.credit_card_number = encrypt(record.credit_card_number)
156
+ # record.send("#{@attribute}=", encrypt(record.send("#{@attribute}")))
113
157
  # end
114
158
  #
115
159
  # def after_save(record)
116
- # record.credit_card_number = decrypt(record.credit_card_number)
160
+ # record.send("#{@attribute}=", decrypt(record.send("#{@attribute}")))
117
161
  # end
118
- #
119
- # alias_method :after_initialize, :after_save
162
+ #
163
+ # alias_method :after_find, :after_save
120
164
  #
121
165
  # private
122
166
  # def encrypt(value)
@@ -124,214 +168,143 @@ module ActiveRecord
124
168
  # end
125
169
  #
126
170
  # def decrypt(value)
127
- # # Secrecy is unvieled
171
+ # # Secrecy is unveiled
128
172
  # end
129
173
  # end
130
174
  #
131
- # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
132
- # a method by the name of the callback messaged.
133
- #
134
- # The callback macros usually accept a symbol for the method they're supposed to run, but you can also pass a "method string",
135
- # which will then be evaluated within the binding of the callback. Example:
175
+ # The callback macros usually accept a symbol for the method they're supposed to run, but you can also
176
+ # pass a "method string", which will then be evaluated within the binding of the callback. Example:
136
177
  #
137
178
  # class Topic < ActiveRecord::Base
138
179
  # before_destroy 'self.class.delete_all "parent_id = #{id}"'
139
180
  # end
140
181
  #
141
- # Notice that single plings (') are used so the #{id} part isn't evaluated until the callback is triggered. Also note that these
142
- # inline callbacks can be stacked just like the regular ones:
182
+ # Notice that single quotes (') are used so the <tt>#{id}</tt> part isn't evaluated until the callback
183
+ # is triggered. Also note that these inline callbacks can be stacked just like the regular ones:
143
184
  #
144
185
  # class Topic < ActiveRecord::Base
145
- # before_destroy 'self.class.delete_all "parent_id = #{id}"',
186
+ # before_destroy 'self.class.delete_all "parent_id = #{id}"',
146
187
  # 'puts "Evaluated after parents are destroyed"'
147
188
  # end
148
189
  #
149
- # == The after_find and after_initialize exceptions
190
+ # == <tt>before_validation*</tt> returning statements
191
+ #
192
+ # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be
193
+ # aborted and <tt>Base#save</tt> will return +false+. If Base#save! is called it will raise a
194
+ # ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object.
195
+ #
196
+ # == Canceling callbacks
197
+ #
198
+ # If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are
199
+ # cancelled. If an <tt>after_*</tt> callback returns +false+, all the later callbacks are cancelled.
200
+ # Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
201
+ # methods on the model, which are called last.
202
+ #
203
+ # == Ordering callbacks
204
+ #
205
+ # Sometimes the code needs that the callbacks execute in a specific order. For example, a +before_destroy+
206
+ # callback (+log_children+ in this case) should be executed before the children get destroyed by the +dependent: destroy+ option.
207
+ #
208
+ # Let's look at the code below:
209
+ #
210
+ # class Topic < ActiveRecord::Base
211
+ # has_many :children, dependent: destroy
212
+ #
213
+ # before_destroy :log_children
214
+ #
215
+ # private
216
+ # def log_children
217
+ # # Child processing
218
+ # end
219
+ # end
220
+ #
221
+ # In this case, the problem is that when the +before_destroy+ callback is executed, the children are not available
222
+ # because the +destroy+ callback gets executed first. You can use the +prepend+ option on the +before_destroy+ callback to avoid this.
223
+ #
224
+ # class Topic < ActiveRecord::Base
225
+ # has_many :children, dependent: destroy
226
+ #
227
+ # before_destroy :log_children, prepend: true
228
+ #
229
+ # private
230
+ # def log_children
231
+ # # Child processing
232
+ # end
233
+ # end
234
+ #
235
+ # This way, the +before_destroy+ gets executed before the <tt>dependent: destroy</tt> is called, and the data is still available.
236
+ #
237
+ # == Transactions
238
+ #
239
+ # The entire callback chain of a +save+, <tt>save!</tt>, or +destroy+ call runs
240
+ # within a transaction. That includes <tt>after_*</tt> hooks. If everything
241
+ # goes fine a COMMIT is executed once the chain has been completed.
242
+ #
243
+ # If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
244
+ # can also trigger a ROLLBACK raising an exception in any of the callbacks,
245
+ # including <tt>after_*</tt> hooks. Note, however, that in that case the client
246
+ # needs to be aware of it because an ordinary +save+ will raise such exception
247
+ # instead of quietly returning +false+.
248
+ #
249
+ # == Debugging callbacks
250
+ #
251
+ # The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object. ActiveModel Callbacks support
252
+ # <tt>:before</tt>, <tt>:after</tt> and <tt>:around</tt> as values for the <tt>kind</tt> property. The <tt>kind</tt> property
253
+ # defines what part of the chain the callback runs in.
254
+ #
255
+ # To find all callbacks in the before_save callback chain:
256
+ #
257
+ # Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
258
+ #
259
+ # Returns an array of callback objects that form the before_save chain.
260
+ #
261
+ # 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:
262
+ #
263
+ # Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:rest_when_dead)
264
+ #
265
+ # Returns true or false depending on whether the proc is contained in the before_save callback chain on a Topic model.
150
266
  #
151
- # Because after_find and after_initialize is called for each object instantiated found by a finder, such as Base.find_all, we've had
152
- # to implement a simple performance constraint (50% more speed on a simple test case). Unlike all the other callbacks, after_find and
153
- # after_initialize can only be declared using an explicit implementation. So using the inheritable callback queue for after_find and
154
- # after_initialize won't work.
155
267
  module Callbacks
156
- CALLBACKS = %w(
157
- after_find after_initialize before_save after_save before_create after_create before_update after_update before_validation
158
- after_validation before_validation_on_create after_validation_on_create before_validation_on_update
159
- after_validation_on_update before_destroy after_destroy
160
- )
161
-
162
- def self.append_features(base) #:nodoc:
163
- super
164
-
165
- base.extend(ClassMethods)
166
- base.class_eval do
167
- class << self
168
- include Observable
169
- alias_method :instantiate_without_callbacks, :instantiate
170
- alias_method :instantiate, :instantiate_with_callbacks
171
- end
172
- end
268
+ extend ActiveSupport::Concern
173
269
 
174
- base.class_eval do
175
- alias_method :initialize_without_callbacks, :initialize
176
- alias_method :initialize, :initialize_with_callbacks
270
+ CALLBACKS = [
271
+ :after_initialize, :after_find, :after_touch, :before_validation, :after_validation,
272
+ :before_save, :around_save, :after_save, :before_create, :around_create,
273
+ :after_create, :before_update, :around_update, :after_update,
274
+ :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
275
+ ]
177
276
 
178
- alias_method :create_or_update_without_callbacks, :create_or_update
179
- alias_method :create_or_update, :create_or_update_with_callbacks
180
-
181
- alias_method :valid_without_callbacks, :valid?
182
- alias_method :valid?, :valid_with_callbacks
183
-
184
- alias_method :create_without_callbacks, :create
185
- alias_method :create, :create_with_callbacks
186
-
187
- alias_method :update_without_callbacks, :update
188
- alias_method :update, :update_with_callbacks
189
-
190
- alias_method :destroy_without_callbacks, :destroy
191
- alias_method :destroy, :destroy_with_callbacks
192
- end
193
-
194
- CALLBACKS.each { |cb| base.class_eval("def self.#{cb}(*methods) write_inheritable_array(\"#{cb}\", methods) end") }
195
- end
196
-
197
- module ClassMethods #:nodoc:
198
- def instantiate_with_callbacks(record)
199
- object = instantiate_without_callbacks(record)
200
- object.callback(:after_find) if object.respond_to_without_attributes?(:after_find)
201
- object.callback(:after_initialize) if object.respond_to_without_attributes?(:after_initialize)
202
- object
203
- end
277
+ module ClassMethods
278
+ include ActiveModel::Callbacks
204
279
  end
205
280
 
206
- # Is called when the object was instantiated by one of the finders, like Base.find.
207
- # def after_find() end
281
+ included do
282
+ include ActiveModel::Validations::Callbacks
208
283
 
209
- # Is called after the object has been instantiated by a call to Base.new.
210
- # def after_initialize() end
211
- def initialize_with_callbacks(attributes = nil) #:nodoc:
212
- initialize_without_callbacks(attributes)
213
- yield self if block_given?
214
- after_initialize if respond_to_without_attributes?(:after_initialize)
284
+ define_model_callbacks :initialize, :find, :touch, :only => :after
285
+ define_model_callbacks :save, :create, :update, :destroy
215
286
  end
216
-
217
- # Is called _before_ Base.save (regardless of whether it's a create or update save).
218
- def before_save() end
219
287
 
220
- # Is called _after_ Base.save (regardless of whether it's a create or update save).
221
- def after_save() end
222
- def create_or_update_with_callbacks #:nodoc:
223
- callback(:before_save)
224
- create_or_update_without_callbacks
225
- callback(:after_save)
288
+ def destroy #:nodoc:
289
+ run_callbacks(:destroy) { super }
226
290
  end
227
291
 
228
- # Is called _before_ Base.save on new objects that haven't been saved yet (no record exists).
229
- def before_create() end
230
-
231
- # Is called _after_ Base.save on new objects that haven't been saved yet (no record exists).
232
- def after_create() end
233
- def create_with_callbacks #:nodoc:
234
- callback(:before_create)
235
- create_without_callbacks
236
- callback(:after_create)
292
+ def touch(*) #:nodoc:
293
+ run_callbacks(:touch) { super }
237
294
  end
238
295
 
239
- # Is called _before_ Base.save on existing objects that has a record.
240
- def before_update() end
241
-
242
- # Is called _after_ Base.save on existing objects that has a record.
243
- def after_update() end
296
+ private
244
297
 
245
- def update_with_callbacks #:nodoc:
246
- callback(:before_update)
247
- update_without_callbacks
248
- callback(:after_update)
298
+ def create_or_update #:nodoc:
299
+ run_callbacks(:save) { super }
249
300
  end
250
301
 
251
- # Is called _before_ Validations.validate (which is part of the Base.save call).
252
- def before_validation() end
253
-
254
- # Is called _after_ Validations.validate (which is part of the Base.save call).
255
- def after_validation() end
256
-
257
- # Is called _before_ Validations.validate (which is part of the Base.save call) on new objects
258
- # that haven't been saved yet (no record exists).
259
- def before_validation_on_create() end
260
-
261
- # Is called _after_ Validations.validate (which is part of the Base.save call) on new objects
262
- # that haven't been saved yet (no record exists).
263
- def after_validation_on_create() end
264
-
265
- # Is called _before_ Validations.validate (which is part of the Base.save call) on
266
- # existing objects that has a record.
267
- def before_validation_on_update() end
268
-
269
- # Is called _after_ Validations.validate (which is part of the Base.save call) on
270
- # existing objects that has a record.
271
- def after_validation_on_update() end
272
-
273
- def valid_with_callbacks #:nodoc:
274
- callback(:before_validation)
275
- if new_record? then callback(:before_validation_on_create) else callback(:before_validation_on_update) end
276
-
277
- result = valid_without_callbacks
278
-
279
- callback(:after_validation)
280
- if new_record? then callback(:after_validation_on_create) else callback(:after_validation_on_update) end
281
-
282
- return result
283
- end
284
-
285
- # Is called _before_ Base.destroy.
286
- def before_destroy() end
287
-
288
- # Is called _after_ Base.destroy (and all the attributes have been frozen).
289
- def after_destroy() end
290
- def destroy_with_callbacks #:nodoc:
291
- callback(:before_destroy)
292
- destroy_without_callbacks
293
- callback(:after_destroy)
294
- end
295
-
296
- def callback(callback_method) #:nodoc:
297
- run_callbacks(callback_method)
298
- send(callback_method)
299
- notify(callback_method)
302
+ def create_record #:nodoc:
303
+ run_callbacks(:create) { super }
300
304
  end
301
305
 
302
- def run_callbacks(callback_method)
303
- filters = self.class.read_inheritable_attribute(callback_method.to_s)
304
- if filters.nil? then return end
305
- filters.each do |filter|
306
- if Symbol === filter
307
- self.send(filter)
308
- elsif String === filter
309
- eval(filter, binding)
310
- elsif filter_block?(filter)
311
- filter.call(self)
312
- elsif filter_class?(filter, callback_method)
313
- filter.send(callback_method, self)
314
- else
315
- raise(
316
- ActiveRecordError,
317
- "Filters need to be either a symbol, string (to be eval'ed), proc/method, or " +
318
- "class implementing a static filter method"
319
- )
320
- end
321
- end
322
- end
323
-
324
- def filter_block?(filter)
325
- filter.respond_to?("call") && (filter.arity == 1 || filter.arity == -1)
326
- end
327
-
328
- def filter_class?(filter, callback_method)
329
- filter.respond_to?(callback_method)
330
- end
331
-
332
- def notify(callback_method) #:nodoc:
333
- self.class.changed
334
- self.class.notify_observers(callback_method, self)
306
+ def update_record(*) #:nodoc:
307
+ run_callbacks(:update) { super }
335
308
  end
336
309
  end
337
- end
310
+ end
@@ -0,0 +1,38 @@
1
+ require 'yaml'
2
+
3
+ module ActiveRecord
4
+ module Coders # :nodoc:
5
+ class YAMLColumn # :nodoc:
6
+
7
+ attr_accessor :object_class
8
+
9
+ def initialize(object_class = Object)
10
+ @object_class = object_class
11
+ end
12
+
13
+ def dump(obj)
14
+ return if obj.nil?
15
+
16
+ unless obj.is_a?(object_class)
17
+ raise SerializationTypeMismatch,
18
+ "Attribute was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
19
+ end
20
+ YAML.dump obj
21
+ end
22
+
23
+ def load(yaml)
24
+ return object_class.new if object_class != Object && yaml.nil?
25
+ return yaml unless yaml.is_a?(String) && yaml =~ /^---/
26
+ obj = YAML.load(yaml)
27
+
28
+ unless obj.is_a?(object_class) || obj.nil?
29
+ raise SerializationTypeMismatch,
30
+ "Attribute was supposed to be a #{object_class}, but was a #{obj.class}"
31
+ end
32
+ obj ||= object_class.new if object_class != Object
33
+
34
+ obj
35
+ end
36
+ end
37
+ end
38
+ end