3 class CallbackDeveloper
< ActiveRecord
::Base
4 set_table_name
'developers'
7 def callback_string(callback_method
)
8 "history << [#{callback_method.to_sym.inspect}, :string]"
11 def callback_proc(callback_method
)
12 Proc
.new
{ |model
| model
.history
<< [callback_method
, :proc] }
15 def define_callback_method(callback_method
)
16 define_method("#{callback_method}_method") do |model
|
17 model
.history
<< [callback_method
, :method]
21 def callback_object(callback_method
)
23 klass
.send(:define_method, callback_method
) do |model
|
24 model
.history
<< [callback_method
, :object]
30 ActiveRecord
::Callbacks::CALLBACKS.each
do |callback_method
|
31 callback_method_sym
= callback_method
.to_sym
32 define_callback_method(callback_method_sym
)
33 send(callback_method
, callback_method_sym
)
34 send(callback_method
, callback_string(callback_method_sym
))
35 send(callback_method
, callback_proc(callback_method_sym
))
36 send(callback_method
, callback_object(callback_method_sym
))
37 send(callback_method
) { |model
| model
.history
<< [callback_method_sym
, :block] }
44 # after_initialize and after_find are invoked only if instance methods have been defined.
52 class ParentDeveloper
< ActiveRecord
::Base
53 set_table_name
'developers'
54 attr_accessor
:after_save_called
55 before_validation
{|record
| record
.after_save_called
= true}
58 class ChildDeveloper
< ParentDeveloper
62 class RecursiveCallbackDeveloper
< ActiveRecord
::Base
63 set_table_name
'developers'
65 before_save
:on_before_save
66 after_save
:on_after_save
68 attr_reader
:on_before_save_called, :on_after_save_called
71 @on_before_save_called ||= 0
72 @on_before_save_called += 1
73 save
unless @on_before_save_called > 1
77 @on_after_save_called ||= 0
78 @on_after_save_called += 1
79 save
unless @on_after_save_called > 1
83 class ImmutableDeveloper
< ActiveRecord
::Base
84 set_table_name
'developers'
86 validates_inclusion_of
:salary, :in => 50000..200000
89 before_destroy
:cancel
102 class ImmutableMethodDeveloper
< ActiveRecord
::Base
103 set_table_name
'developers'
105 validates_inclusion_of
:salary, :in => 50000..200000
122 class CallbackCancellationDeveloper
< ActiveRecord
::Base
123 set_table_name
'developers'
129 class CallbacksTest
< ActiveRecord
::TestCase
133 david
= CallbackDeveloper
.new
135 [ :after_initialize, :string ],
136 [ :after_initialize, :proc ],
137 [ :after_initialize, :object ],
138 [ :after_initialize, :block ],
143 david
= CallbackDeveloper
.find(1)
145 [ :after_find, :string ],
146 [ :after_find, :proc ],
147 [ :after_find, :object ],
148 [ :after_find, :block ],
149 [ :after_initialize, :string ],
150 [ :after_initialize, :proc ],
151 [ :after_initialize, :object ],
152 [ :after_initialize, :block ],
157 david
= CallbackDeveloper
.new
160 [ :after_initialize, :string ],
161 [ :after_initialize, :proc ],
162 [ :after_initialize, :object ],
163 [ :after_initialize, :block ],
164 [ :before_validation, :string ],
165 [ :before_validation, :proc ],
166 [ :before_validation, :object ],
167 [ :before_validation, :block ],
168 [ :before_validation_on_create, :string ],
169 [ :before_validation_on_create, :proc ],
170 [ :before_validation_on_create, :object ],
171 [ :before_validation_on_create, :block ],
172 [ :after_validation, :string ],
173 [ :after_validation, :proc ],
174 [ :after_validation, :object ],
175 [ :after_validation, :block ],
176 [ :after_validation_on_create, :string ],
177 [ :after_validation_on_create, :proc ],
178 [ :after_validation_on_create, :object ],
179 [ :after_validation_on_create, :block ]
183 def test_existing_valid
?
184 david
= CallbackDeveloper
.find(1)
187 [ :after_find, :string ],
188 [ :after_find, :proc ],
189 [ :after_find, :object ],
190 [ :after_find, :block ],
191 [ :after_initialize, :string ],
192 [ :after_initialize, :proc ],
193 [ :after_initialize, :object ],
194 [ :after_initialize, :block ],
195 [ :before_validation, :string ],
196 [ :before_validation, :proc ],
197 [ :before_validation, :object ],
198 [ :before_validation, :block ],
199 [ :before_validation_on_update, :string ],
200 [ :before_validation_on_update, :proc ],
201 [ :before_validation_on_update, :object ],
202 [ :before_validation_on_update, :block ],
203 [ :after_validation, :string ],
204 [ :after_validation, :proc ],
205 [ :after_validation, :object ],
206 [ :after_validation, :block ],
207 [ :after_validation_on_update, :string ],
208 [ :after_validation_on_update, :proc ],
209 [ :after_validation_on_update, :object ],
210 [ :after_validation_on_update, :block ]
215 david
= CallbackDeveloper
.create('name' => 'David', 'salary' => 1000000)
217 [ :after_initialize, :string ],
218 [ :after_initialize, :proc ],
219 [ :after_initialize, :object ],
220 [ :after_initialize, :block ],
221 [ :before_validation, :string ],
222 [ :before_validation, :proc ],
223 [ :before_validation, :object ],
224 [ :before_validation, :block ],
225 [ :before_validation_on_create, :string ],
226 [ :before_validation_on_create, :proc ],
227 [ :before_validation_on_create, :object ],
228 [ :before_validation_on_create, :block ],
229 [ :after_validation, :string ],
230 [ :after_validation, :proc ],
231 [ :after_validation, :object ],
232 [ :after_validation, :block ],
233 [ :after_validation_on_create, :string ],
234 [ :after_validation_on_create, :proc ],
235 [ :after_validation_on_create, :object ],
236 [ :after_validation_on_create, :block ],
237 [ :before_save, :string ],
238 [ :before_save, :proc ],
239 [ :before_save, :object ],
240 [ :before_save, :block ],
241 [ :before_create, :string ],
242 [ :before_create, :proc ],
243 [ :before_create, :object ],
244 [ :before_create, :block ],
245 [ :after_create, :string ],
246 [ :after_create, :proc ],
247 [ :after_create, :object ],
248 [ :after_create, :block ],
249 [ :after_save, :string ],
250 [ :after_save, :proc ],
251 [ :after_save, :object ],
252 [ :after_save, :block ]
257 david
= CallbackDeveloper
.find(1)
260 [ :after_find, :string ],
261 [ :after_find, :proc ],
262 [ :after_find, :object ],
263 [ :after_find, :block ],
264 [ :after_initialize, :string ],
265 [ :after_initialize, :proc ],
266 [ :after_initialize, :object ],
267 [ :after_initialize, :block ],
268 [ :before_validation, :string ],
269 [ :before_validation, :proc ],
270 [ :before_validation, :object ],
271 [ :before_validation, :block ],
272 [ :before_validation_on_update, :string ],
273 [ :before_validation_on_update, :proc ],
274 [ :before_validation_on_update, :object ],
275 [ :before_validation_on_update, :block ],
276 [ :after_validation, :string ],
277 [ :after_validation, :proc ],
278 [ :after_validation, :object ],
279 [ :after_validation, :block ],
280 [ :after_validation_on_update, :string ],
281 [ :after_validation_on_update, :proc ],
282 [ :after_validation_on_update, :object ],
283 [ :after_validation_on_update, :block ],
284 [ :before_save, :string ],
285 [ :before_save, :proc ],
286 [ :before_save, :object ],
287 [ :before_save, :block ],
288 [ :before_update, :string ],
289 [ :before_update, :proc ],
290 [ :before_update, :object ],
291 [ :before_update, :block ],
292 [ :after_update, :string ],
293 [ :after_update, :proc ],
294 [ :after_update, :object ],
295 [ :after_update, :block ],
296 [ :after_save, :string ],
297 [ :after_save, :proc ],
298 [ :after_save, :object ],
299 [ :after_save, :block ]
304 david
= CallbackDeveloper
.find(1)
307 [ :after_find, :string ],
308 [ :after_find, :proc ],
309 [ :after_find, :object ],
310 [ :after_find, :block ],
311 [ :after_initialize, :string ],
312 [ :after_initialize, :proc ],
313 [ :after_initialize, :object ],
314 [ :after_initialize, :block ],
315 [ :before_destroy, :string ],
316 [ :before_destroy, :proc ],
317 [ :before_destroy, :object ],
318 [ :before_destroy, :block ],
319 [ :after_destroy, :string ],
320 [ :after_destroy, :proc ],
321 [ :after_destroy, :object ],
322 [ :after_destroy, :block ]
327 david
= CallbackDeveloper
.find(1)
328 CallbackDeveloper
.delete(david
.id
)
330 [ :after_find, :string ],
331 [ :after_find, :proc ],
332 [ :after_find, :object ],
333 [ :after_find, :block ],
334 [ :after_initialize, :string ],
335 [ :after_initialize, :proc ],
336 [ :after_initialize, :object ],
337 [ :after_initialize, :block ],
341 def test_before_save_returning_false
342 david
= ImmutableDeveloper
.find(1)
345 assert_raises(ActiveRecord
::RecordNotSaved) { david
.save
! }
347 david
= ImmutableDeveloper
.find(1)
348 david
.salary
= 10_000_000
351 assert_raises(ActiveRecord
::RecordInvalid) { david
.save
! }
354 def test_before_create_returning_false
355 someone
= CallbackCancellationDeveloper
.new
356 assert someone
.valid
?
360 def test_before_destroy_returning_false
361 david
= ImmutableDeveloper
.find(1)
362 assert
!david
.destroy
363 assert_not_nil ImmutableDeveloper
.find_by_id(1)
366 def test_zzz_callback_returning_false
# must be run last since we modify CallbackDeveloper
367 david
= CallbackDeveloper
.find(1)
368 CallbackDeveloper
.before_validation proc
{ |model
| model
.history
<< [:before_validation, :returning_false]; return false }
369 CallbackDeveloper
.before_validation proc
{ |model
| model
.history
<< [:before_validation, :should_never_get_here] }
372 [ :after_find, :string ],
373 [ :after_find, :proc ],
374 [ :after_find, :object ],
375 [ :after_find, :block ],
376 [ :after_initialize, :string ],
377 [ :after_initialize, :proc ],
378 [ :after_initialize, :object ],
379 [ :after_initialize, :block ],
380 [ :before_validation, :string ],
381 [ :before_validation, :proc ],
382 [ :before_validation, :object ],
383 [ :before_validation, :block ],
384 [ :before_validation, :returning_false ]
388 def test_inheritence_of_callbacks
389 parent
= ParentDeveloper
.new
390 assert
!parent
.after_save_called
392 assert parent
.after_save_called
394 child
= ChildDeveloper
.new
395 assert
!child
.after_save_called
397 assert child
.after_save_called