activerecord 1.0.0 → 3.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.
- data/CHANGELOG +5518 -76
- data/README.rdoc +222 -0
- data/examples/performance.rb +162 -0
- data/examples/simple.rb +14 -0
- data/lib/active_record/aggregations.rb +192 -80
- data/lib/active_record/association_preload.rb +403 -0
- data/lib/active_record/associations/association_collection.rb +545 -53
- data/lib/active_record/associations/association_proxy.rb +295 -0
- data/lib/active_record/associations/belongs_to_association.rb +91 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +78 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +127 -36
- data/lib/active_record/associations/has_many_association.rb +108 -84
- data/lib/active_record/associations/has_many_through_association.rb +116 -0
- data/lib/active_record/associations/has_one_association.rb +143 -0
- data/lib/active_record/associations/has_one_through_association.rb +40 -0
- data/lib/active_record/associations/through_association_scope.rb +154 -0
- data/lib/active_record/associations.rb +2086 -368
- data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
- data/lib/active_record/attribute_methods/dirty.rb +95 -0
- data/lib/active_record/attribute_methods/primary_key.rb +50 -0
- data/lib/active_record/attribute_methods/query.rb +39 -0
- data/lib/active_record/attribute_methods/read.rb +116 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -0
- data/lib/active_record/attribute_methods/write.rb +37 -0
- data/lib/active_record/attribute_methods.rb +60 -0
- data/lib/active_record/autosave_association.rb +369 -0
- data/lib/active_record/base.rb +1603 -721
- data/lib/active_record/callbacks.rb +176 -225
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +365 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +113 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +329 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +739 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +543 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -279
- data/lib/active_record/connection_adapters/mysql_adapter.rb +594 -82
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +988 -135
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +365 -71
- data/lib/active_record/counter_cache.rb +115 -0
- data/lib/active_record/dynamic_finder_match.rb +53 -0
- data/lib/active_record/dynamic_scope_match.rb +32 -0
- data/lib/active_record/errors.rb +172 -0
- data/lib/active_record/fixtures.rb +941 -105
- data/lib/active_record/locale/en.yml +40 -0
- data/lib/active_record/locking/optimistic.rb +172 -0
- data/lib/active_record/locking/pessimistic.rb +55 -0
- data/lib/active_record/log_subscriber.rb +48 -0
- data/lib/active_record/migration.rb +617 -0
- data/lib/active_record/named_scope.rb +138 -0
- data/lib/active_record/nested_attributes.rb +417 -0
- data/lib/active_record/observer.rb +105 -36
- data/lib/active_record/persistence.rb +291 -0
- data/lib/active_record/query_cache.rb +36 -0
- data/lib/active_record/railtie.rb +91 -0
- data/lib/active_record/railties/controller_runtime.rb +38 -0
- data/lib/active_record/railties/databases.rake +512 -0
- data/lib/active_record/reflection.rb +364 -87
- data/lib/active_record/relation/batches.rb +89 -0
- data/lib/active_record/relation/calculations.rb +286 -0
- data/lib/active_record/relation/finder_methods.rb +355 -0
- data/lib/active_record/relation/predicate_builder.rb +41 -0
- data/lib/active_record/relation/query_methods.rb +261 -0
- data/lib/active_record/relation/spawn_methods.rb +112 -0
- data/lib/active_record/relation.rb +393 -0
- data/lib/active_record/schema.rb +59 -0
- data/lib/active_record/schema_dumper.rb +195 -0
- data/lib/active_record/serialization.rb +60 -0
- data/lib/active_record/serializers/xml_serializer.rb +244 -0
- data/lib/active_record/session_store.rb +340 -0
- data/lib/active_record/test_case.rb +67 -0
- data/lib/active_record/timestamp.rb +88 -0
- data/lib/active_record/transactions.rb +329 -75
- data/lib/active_record/validations/associated.rb +48 -0
- data/lib/active_record/validations/uniqueness.rb +185 -0
- data/lib/active_record/validations.rb +58 -179
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record.rb +100 -24
- data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
- data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
- data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
- data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
- data/lib/rails/generators/active_record.rb +27 -0
- metadata +216 -158
- data/README +0 -361
- data/RUNNING_UNIT_TESTS +0 -36
- data/dev-utils/eval_debugger.rb +0 -9
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -88
- data/install.rb +0 -60
- data/lib/active_record/deprecated_associations.rb +0 -70
- data/lib/active_record/support/class_attribute_accessors.rb +0 -43
- data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
- data/lib/active_record/support/clean_logger.rb +0 -10
- data/lib/active_record/support/inflector.rb +0 -70
- data/lib/active_record/vendor/mysql.rb +0 -1117
- data/lib/active_record/vendor/simple.rb +0 -702
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -59
- data/rakefile +0 -122
- data/test/abstract_unit.rb +0 -16
- data/test/aggregations_test.rb +0 -34
- data/test/all.sh +0 -8
- data/test/associations_test.rb +0 -477
- data/test/base_test.rb +0 -513
- data/test/class_inheritable_attributes_test.rb +0 -33
- data/test/connections/native_mysql/connection.rb +0 -24
- data/test/connections/native_postgresql/connection.rb +0 -24
- data/test/connections/native_sqlite/connection.rb +0 -24
- data/test/deprecated_associations_test.rb +0 -336
- data/test/finder_test.rb +0 -67
- data/test/fixtures/accounts/signals37 +0 -3
- data/test/fixtures/accounts/unknown +0 -2
- data/test/fixtures/auto_id.rb +0 -4
- data/test/fixtures/column_name.rb +0 -3
- data/test/fixtures/companies/first_client +0 -6
- data/test/fixtures/companies/first_firm +0 -4
- data/test/fixtures/companies/second_client +0 -6
- data/test/fixtures/company.rb +0 -37
- data/test/fixtures/company_in_module.rb +0 -33
- data/test/fixtures/course.rb +0 -3
- data/test/fixtures/courses/java +0 -2
- data/test/fixtures/courses/ruby +0 -2
- data/test/fixtures/customer.rb +0 -30
- data/test/fixtures/customers/david +0 -6
- data/test/fixtures/db_definitions/mysql.sql +0 -96
- data/test/fixtures/db_definitions/mysql2.sql +0 -4
- data/test/fixtures/db_definitions/postgresql.sql +0 -113
- data/test/fixtures/db_definitions/postgresql2.sql +0 -4
- data/test/fixtures/db_definitions/sqlite.sql +0 -85
- data/test/fixtures/db_definitions/sqlite2.sql +0 -4
- data/test/fixtures/default.rb +0 -2
- data/test/fixtures/developer.rb +0 -8
- data/test/fixtures/developers/david +0 -2
- data/test/fixtures/developers/jamis +0 -2
- data/test/fixtures/developers_projects/david_action_controller +0 -2
- data/test/fixtures/developers_projects/david_active_record +0 -2
- data/test/fixtures/developers_projects/jamis_active_record +0 -2
- data/test/fixtures/entrant.rb +0 -3
- data/test/fixtures/entrants/first +0 -3
- data/test/fixtures/entrants/second +0 -3
- data/test/fixtures/entrants/third +0 -3
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/movie.rb +0 -5
- data/test/fixtures/movies/first +0 -2
- data/test/fixtures/movies/second +0 -2
- data/test/fixtures/project.rb +0 -3
- data/test/fixtures/projects/action_controller +0 -2
- data/test/fixtures/projects/active_record +0 -2
- data/test/fixtures/reply.rb +0 -21
- data/test/fixtures/subscriber.rb +0 -5
- data/test/fixtures/subscribers/first +0 -2
- data/test/fixtures/subscribers/second +0 -2
- data/test/fixtures/topic.rb +0 -20
- data/test/fixtures/topics/first +0 -9
- data/test/fixtures/topics/second +0 -8
- data/test/fixtures_test.rb +0 -20
- data/test/inflector_test.rb +0 -104
- data/test/inheritance_test.rb +0 -125
- data/test/lifecycle_test.rb +0 -110
- data/test/modules_test.rb +0 -21
- data/test/multiple_db_test.rb +0 -46
- data/test/pk_test.rb +0 -57
- data/test/reflection_test.rb +0 -78
- data/test/thread_safety_test.rb +0 -33
- data/test/transactions_test.rb +0 -83
- data/test/unconnected_test.rb +0 -24
- data/test/validations_test.rb +0 -126
@@ -1,57 +1,63 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# before
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# * (
|
13
|
-
# * (
|
14
|
-
# * (
|
15
|
-
# * (-)
|
16
|
-
# * (
|
17
|
-
# * (
|
18
|
-
# * (
|
19
|
-
# * (
|
20
|
-
# * (
|
21
|
-
# * (
|
22
|
-
# * (
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
4
|
+
# = Active Record Callbacks
|
5
|
+
#
|
6
|
+
# Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
|
7
|
+
# 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:
|
11
|
+
#
|
12
|
+
# * (-) <tt>save</tt>
|
13
|
+
# * (-) <tt>valid</tt>
|
14
|
+
# * (1) <tt>before_validation</tt>
|
15
|
+
# * (-) <tt>validate</tt>
|
16
|
+
# * (2) <tt>after_validation</tt>
|
17
|
+
# * (3) <tt>before_save</tt>
|
18
|
+
# * (4) <tt>before_create</tt>
|
19
|
+
# * (-) <tt>create</tt>
|
20
|
+
# * (5) <tt>after_create</tt>
|
21
|
+
# * (6) <tt>after_save</tt>
|
22
|
+
# * (7) <tt>after_commit</tt>
|
23
|
+
#
|
24
|
+
# 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
|
26
|
+
# <tt>after_rollback</tt>.
|
27
|
+
#
|
28
|
+
# That's a total of ten callbacks, which gives you immense power to react and prepare for each state in the
|
29
|
+
# Active Record life cycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar,
|
30
|
+
# except that each <tt>_on_create</tt> callback is replaced by the corresponding <tt>_on_update</tt> callback.
|
26
31
|
#
|
27
32
|
# Examples:
|
28
33
|
# class CreditCard < ActiveRecord::Base
|
29
|
-
# # Strip everything but digits, so the user can specify "555 234 34" or
|
34
|
+
# # Strip everything but digits, so the user can specify "555 234 34" or
|
30
35
|
# # "5552-3434" or both will mean "55523434"
|
31
|
-
#
|
36
|
+
# before_validation(:on => :create) do
|
32
37
|
# self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
|
33
38
|
# end
|
34
39
|
# end
|
35
40
|
#
|
36
41
|
# class Subscription < ActiveRecord::Base
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
42
|
+
# before_create :record_signup
|
43
|
+
#
|
44
|
+
# private
|
45
|
+
# def record_signup
|
46
|
+
# self.signed_up_on = Date.today
|
47
|
+
# end
|
41
48
|
# end
|
42
49
|
#
|
43
50
|
# class Firm < ActiveRecord::Base
|
44
51
|
# # Destroys the associated clients and people when the firm is destroyed
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
# end
|
52
|
+
# before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
|
53
|
+
# before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
|
54
|
+
# end
|
49
55
|
#
|
50
56
|
# == Inheritable callback queues
|
51
57
|
#
|
52
|
-
# Besides the
|
53
|
-
# Their main advantage is that the macros add behavior into a callback
|
54
|
-
# hierarchy.
|
58
|
+
# Besides the overwritable callback methods, it's also possible to register callbacks through the
|
59
|
+
# use of the callback macros. Their main advantage is that the macros add behavior into a callback
|
60
|
+
# queue that is kept intact down through an inheritance hierarchy.
|
55
61
|
#
|
56
62
|
# class Topic < ActiveRecord::Base
|
57
63
|
# before_destroy :destroy_author
|
@@ -61,9 +67,9 @@ module ActiveRecord
|
|
61
67
|
# before_destroy :destroy_readers
|
62
68
|
# end
|
63
69
|
#
|
64
|
-
# Now, when Topic#destroy is run only +destroy_author+ is called. When Reply#destroy is
|
65
|
-
# +destroy_readers+
|
66
|
-
#
|
70
|
+
# Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is
|
71
|
+
# run, both +destroy_author+ and +destroy_readers+ are called. Contrast this to the following situation
|
72
|
+
# where the +before_destroy+ methis is overriden:
|
67
73
|
#
|
68
74
|
# class Topic < ActiveRecord::Base
|
69
75
|
# def before_destroy() destroy_author end
|
@@ -73,16 +79,21 @@ module ActiveRecord
|
|
73
79
|
# def before_destroy() destroy_readers end
|
74
80
|
# end
|
75
81
|
#
|
76
|
-
# In that case, Reply#destroy would only run +destroy_readers+ and _not_ +destroy_author+.
|
77
|
-
# you want to ensure that a certain callback is called for the entire
|
78
|
-
#
|
82
|
+
# In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
|
83
|
+
# So, use the callback macros when you want to ensure that a certain callback is called for the entire
|
84
|
+
# hierarchy, and use the regular overwriteable methods when you want to leave it up to each descendant
|
85
|
+
# to decide whether they want to call +super+ and trigger the inherited callbacks.
|
86
|
+
#
|
87
|
+
# *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
|
88
|
+
# callbacks before specifying the associations. Otherwise, you might trigger the loading of a
|
89
|
+
# child before the parent has registered the callbacks and they won't be inherited.
|
79
90
|
#
|
80
91
|
# == Types of callbacks
|
81
92
|
#
|
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
|
84
|
-
# recommended approaches, inline methods using a proc
|
85
|
-
# eval methods are deprecated.
|
93
|
+
# There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
|
94
|
+
# inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects
|
95
|
+
# are the recommended approaches, inline methods using a proc are sometimes appropriate (such as for
|
96
|
+
# creating mix-ins), and inline eval methods are deprecated.
|
86
97
|
#
|
87
98
|
# The method reference callbacks work by specifying a protected or private method available in the object, like this:
|
88
99
|
#
|
@@ -98,6 +109,37 @@ module ActiveRecord
|
|
98
109
|
# The callback objects have methods named after the callback called with the record as the only parameter, such as:
|
99
110
|
#
|
100
111
|
# class BankAccount < ActiveRecord::Base
|
112
|
+
# before_save EncryptionWrapper.new
|
113
|
+
# after_save EncryptionWrapper.new
|
114
|
+
# after_initialize EncryptionWrapper.new
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# class EncryptionWrapper
|
118
|
+
# def before_save(record)
|
119
|
+
# record.credit_card_number = encrypt(record.credit_card_number)
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# def after_save(record)
|
123
|
+
# record.credit_card_number = decrypt(record.credit_card_number)
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# alias_method :after_find, :after_save
|
127
|
+
#
|
128
|
+
# private
|
129
|
+
# def encrypt(value)
|
130
|
+
# # Secrecy is committed
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# def decrypt(value)
|
134
|
+
# # Secrecy is unveiled
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
|
139
|
+
# a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other
|
140
|
+
# initialization data such as the name of the attribute to work with:
|
141
|
+
#
|
142
|
+
# class BankAccount < ActiveRecord::Base
|
101
143
|
# before_save EncryptionWrapper.new("credit_card_number")
|
102
144
|
# after_save EncryptionWrapper.new("credit_card_number")
|
103
145
|
# after_initialize EncryptionWrapper.new("credit_card_number")
|
@@ -109,14 +151,14 @@ module ActiveRecord
|
|
109
151
|
# end
|
110
152
|
#
|
111
153
|
# def before_save(record)
|
112
|
-
# record.
|
154
|
+
# record.send("#{@attribute}=", encrypt(record.send("#{@attribute}")))
|
113
155
|
# end
|
114
156
|
#
|
115
157
|
# def after_save(record)
|
116
|
-
# record.
|
158
|
+
# record.send("#{@attribute}=", decrypt(record.send("#{@attribute}")))
|
117
159
|
# end
|
118
|
-
#
|
119
|
-
# alias_method :
|
160
|
+
#
|
161
|
+
# alias_method :after_find, :after_save
|
120
162
|
#
|
121
163
|
# private
|
122
164
|
# def encrypt(value)
|
@@ -124,214 +166,123 @@ module ActiveRecord
|
|
124
166
|
# end
|
125
167
|
#
|
126
168
|
# def decrypt(value)
|
127
|
-
# # Secrecy is
|
169
|
+
# # Secrecy is unveiled
|
128
170
|
# end
|
129
171
|
# end
|
130
172
|
#
|
131
|
-
#
|
132
|
-
# a method
|
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:
|
173
|
+
# The callback macros usually accept a symbol for the method they're supposed to run, but you can also
|
174
|
+
# pass a "method string", which will then be evaluated within the binding of the callback. Example:
|
136
175
|
#
|
137
176
|
# class Topic < ActiveRecord::Base
|
138
177
|
# before_destroy 'self.class.delete_all "parent_id = #{id}"'
|
139
178
|
# end
|
140
179
|
#
|
141
|
-
# Notice that single
|
142
|
-
# inline callbacks can be stacked just like the regular ones:
|
180
|
+
# Notice that single quotes (') are used so the <tt>#{id}</tt> part isn't evaluated until the callback
|
181
|
+
# is triggered. Also note that these inline callbacks can be stacked just like the regular ones:
|
143
182
|
#
|
144
183
|
# class Topic < ActiveRecord::Base
|
145
|
-
# before_destroy 'self.class.delete_all "parent_id = #{id}"',
|
184
|
+
# before_destroy 'self.class.delete_all "parent_id = #{id}"',
|
146
185
|
# 'puts "Evaluated after parents are destroyed"'
|
147
186
|
# end
|
148
187
|
#
|
149
|
-
# == The after_find and after_initialize exceptions
|
188
|
+
# == The +after_find+ and +after_initialize+ exceptions
|
189
|
+
#
|
190
|
+
# Because +after_find+ and +after_initialize+ are called for each object found and instantiated by a finder,
|
191
|
+
# such as <tt>Base.find(:all)</tt>, we've had to implement a simple performance constraint (50% more speed
|
192
|
+
# on a simple test case). Unlike all the other callbacks, +after_find+ and +after_initialize+ will only be
|
193
|
+
# run if an explicit implementation is defined (<tt>def after_find</tt>). In that case, all of the
|
194
|
+
# callback types will be called.
|
195
|
+
#
|
196
|
+
# == <tt>before_validation*</tt> returning statements
|
197
|
+
#
|
198
|
+
# If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be
|
199
|
+
# aborted and <tt>Base#save</tt> will return +false+. If Base#save! is called it will raise a
|
200
|
+
# ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object.
|
201
|
+
#
|
202
|
+
# == Canceling callbacks
|
203
|
+
#
|
204
|
+
# If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are
|
205
|
+
# cancelled. If an <tt>after_*</tt> callback returns +false+, all the later callbacks are cancelled.
|
206
|
+
# Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
|
207
|
+
# methods on the model, which are called last.
|
208
|
+
#
|
209
|
+
# == Transactions
|
210
|
+
#
|
211
|
+
# The entire callback chain of a +save+, <tt>save!</tt>, or +destroy+ call runs
|
212
|
+
# within a transaction. That includes <tt>after_*</tt> hooks. If everything
|
213
|
+
# goes fine a COMMIT is executed once the chain has been completed.
|
214
|
+
#
|
215
|
+
# If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
|
216
|
+
# can also trigger a ROLLBACK raising an exception in any of the callbacks,
|
217
|
+
# including <tt>after_*</tt> hooks. Note, however, that in that case the client
|
218
|
+
# needs to be aware of it because an ordinary +save+ will raise such exception
|
219
|
+
# instead of quietly returning +false+.
|
220
|
+
#
|
221
|
+
# == Debugging callbacks
|
222
|
+
#
|
223
|
+
# To list the methods and procs registered with a particular callback, append <tt>_callback_chain</tt> to
|
224
|
+
# the callback name that you wish to list and send that to your class from the Rails console:
|
225
|
+
#
|
226
|
+
# >> Topic.after_save_callback_chain
|
227
|
+
# => [#<ActiveSupport::Callbacks::Callback:0x3f6a448
|
228
|
+
# @method=#<Proc:0x03f9a42c@/Users/foo/bar/app/models/topic.rb:43>, kind:after_save, identifiernil,
|
229
|
+
# options{}]
|
150
230
|
#
|
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
231
|
module Callbacks
|
156
|
-
|
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
|
-
)
|
232
|
+
extend ActiveSupport::Concern
|
161
233
|
|
162
|
-
|
163
|
-
|
234
|
+
CALLBACKS = [
|
235
|
+
:after_initialize, :after_find, :after_touch, :before_validation, :after_validation,
|
236
|
+
:before_save, :around_save, :after_save, :before_create, :around_create,
|
237
|
+
:after_create, :before_update, :around_update, :after_update,
|
238
|
+
:before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
|
239
|
+
]
|
164
240
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
include Observable
|
169
|
-
alias_method :instantiate_without_callbacks, :instantiate
|
170
|
-
alias_method :instantiate, :instantiate_with_callbacks
|
171
|
-
end
|
172
|
-
end
|
241
|
+
included do
|
242
|
+
extend ActiveModel::Callbacks
|
243
|
+
include ActiveModel::Validations::Callbacks
|
173
244
|
|
174
|
-
|
175
|
-
|
176
|
-
alias_method :initialize, :initialize_with_callbacks
|
177
|
-
|
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") }
|
245
|
+
define_model_callbacks :initialize, :find, :touch, :only => :after
|
246
|
+
define_model_callbacks :save, :create, :update, :destroy
|
195
247
|
end
|
196
248
|
|
197
|
-
module ClassMethods
|
198
|
-
def
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
249
|
+
module ClassMethods
|
250
|
+
def method_added(meth)
|
251
|
+
super
|
252
|
+
if CALLBACKS.include?(meth.to_sym)
|
253
|
+
ActiveSupport::Deprecation.warn("Base##{meth} has been deprecated, please use Base.#{meth} :method instead", caller[0,1])
|
254
|
+
send(meth.to_sym, meth.to_sym)
|
255
|
+
end
|
203
256
|
end
|
204
257
|
end
|
205
258
|
|
206
|
-
|
207
|
-
|
208
|
-
|
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)
|
259
|
+
def destroy #:nodoc:
|
260
|
+
_run_destroy_callbacks { super }
|
215
261
|
end
|
216
|
-
|
217
|
-
# Is called _before_ Base.save (regardless of whether it's a create or update save).
|
218
|
-
def before_save() end
|
219
262
|
|
220
|
-
|
221
|
-
|
222
|
-
def create_or_update_with_callbacks #:nodoc:
|
223
|
-
callback(:before_save)
|
224
|
-
create_or_update_without_callbacks
|
225
|
-
callback(:after_save)
|
263
|
+
def touch(*) #:nodoc:
|
264
|
+
_run_touch_callbacks { super }
|
226
265
|
end
|
227
266
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
def create_with_callbacks #:nodoc:
|
234
|
-
callback(:before_create)
|
235
|
-
create_without_callbacks
|
236
|
-
callback(:after_create)
|
237
|
-
end
|
238
|
-
|
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
|
244
|
-
|
245
|
-
def update_with_callbacks #:nodoc:
|
246
|
-
callback(:before_update)
|
247
|
-
update_without_callbacks
|
248
|
-
callback(:after_update)
|
249
|
-
end
|
250
|
-
|
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
|
267
|
+
def deprecated_callback_method(symbol) #:nodoc:
|
268
|
+
if respond_to?(symbol, true)
|
269
|
+
ActiveSupport::Deprecation.warn("Overwriting #{symbol} in your models has been deprecated, please use Base##{symbol} :method_name instead")
|
270
|
+
send(symbol)
|
271
|
+
end
|
283
272
|
end
|
284
273
|
|
285
|
-
|
286
|
-
def before_destroy() end
|
274
|
+
private
|
287
275
|
|
288
|
-
|
289
|
-
|
290
|
-
def destroy_with_callbacks #:nodoc:
|
291
|
-
callback(:before_destroy)
|
292
|
-
destroy_without_callbacks
|
293
|
-
callback(:after_destroy)
|
276
|
+
def create_or_update #:nodoc:
|
277
|
+
_run_save_callbacks { super }
|
294
278
|
end
|
295
279
|
|
296
|
-
def
|
297
|
-
|
298
|
-
send(callback_method)
|
299
|
-
notify(callback_method)
|
280
|
+
def create #:nodoc:
|
281
|
+
_run_create_callbacks { super }
|
300
282
|
end
|
301
283
|
|
302
|
-
def
|
303
|
-
|
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)
|
284
|
+
def update(*) #:nodoc:
|
285
|
+
_run_update_callbacks { super }
|
335
286
|
end
|
336
287
|
end
|
337
|
-
end
|
288
|
+
end
|