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'
125 attr_reader
:after_save_called, :after_create_called, :after_update_called, :after_destroy_called
126 attr_accessor
:cancel_before_save, :cancel_before_create, :cancel_before_update, :cancel_before_destroy
128 def before_save
; !@cancel_before_save; end
129 def before_create
; !@cancel_before_create; end
130 def before_update
; !@cancel_before_update; end
131 def before_destroy
; !@cancel_before_destroy; end
133 def after_save
; @after_save_called = true; end
134 def after_update
; @after_update_called = true; end
135 def after_create
; @after_create_called = true; end
136 def after_destroy
; @after_destroy_called = true; end
139 class CallbacksTest
< ActiveRecord
::TestCase
143 david
= CallbackDeveloper
.new
145 [ :after_initialize, :string ],
146 [ :after_initialize, :proc ],
147 [ :after_initialize, :object ],
148 [ :after_initialize, :block ],
153 david
= CallbackDeveloper
.find(1)
155 [ :after_find, :string ],
156 [ :after_find, :proc ],
157 [ :after_find, :object ],
158 [ :after_find, :block ],
159 [ :after_initialize, :string ],
160 [ :after_initialize, :proc ],
161 [ :after_initialize, :object ],
162 [ :after_initialize, :block ],
167 david
= CallbackDeveloper
.new
170 [ :after_initialize, :string ],
171 [ :after_initialize, :proc ],
172 [ :after_initialize, :object ],
173 [ :after_initialize, :block ],
174 [ :before_validation, :string ],
175 [ :before_validation, :proc ],
176 [ :before_validation, :object ],
177 [ :before_validation, :block ],
178 [ :before_validation_on_create, :string ],
179 [ :before_validation_on_create, :proc ],
180 [ :before_validation_on_create, :object ],
181 [ :before_validation_on_create, :block ],
182 [ :after_validation, :string ],
183 [ :after_validation, :proc ],
184 [ :after_validation, :object ],
185 [ :after_validation, :block ],
186 [ :after_validation_on_create, :string ],
187 [ :after_validation_on_create, :proc ],
188 [ :after_validation_on_create, :object ],
189 [ :after_validation_on_create, :block ]
193 def test_existing_valid
?
194 david
= CallbackDeveloper
.find(1)
197 [ :after_find, :string ],
198 [ :after_find, :proc ],
199 [ :after_find, :object ],
200 [ :after_find, :block ],
201 [ :after_initialize, :string ],
202 [ :after_initialize, :proc ],
203 [ :after_initialize, :object ],
204 [ :after_initialize, :block ],
205 [ :before_validation, :string ],
206 [ :before_validation, :proc ],
207 [ :before_validation, :object ],
208 [ :before_validation, :block ],
209 [ :before_validation_on_update, :string ],
210 [ :before_validation_on_update, :proc ],
211 [ :before_validation_on_update, :object ],
212 [ :before_validation_on_update, :block ],
213 [ :after_validation, :string ],
214 [ :after_validation, :proc ],
215 [ :after_validation, :object ],
216 [ :after_validation, :block ],
217 [ :after_validation_on_update, :string ],
218 [ :after_validation_on_update, :proc ],
219 [ :after_validation_on_update, :object ],
220 [ :after_validation_on_update, :block ]
225 david
= CallbackDeveloper
.create('name' => 'David', 'salary' => 1000000)
227 [ :after_initialize, :string ],
228 [ :after_initialize, :proc ],
229 [ :after_initialize, :object ],
230 [ :after_initialize, :block ],
231 [ :before_validation, :string ],
232 [ :before_validation, :proc ],
233 [ :before_validation, :object ],
234 [ :before_validation, :block ],
235 [ :before_validation_on_create, :string ],
236 [ :before_validation_on_create, :proc ],
237 [ :before_validation_on_create, :object ],
238 [ :before_validation_on_create, :block ],
239 [ :after_validation, :string ],
240 [ :after_validation, :proc ],
241 [ :after_validation, :object ],
242 [ :after_validation, :block ],
243 [ :after_validation_on_create, :string ],
244 [ :after_validation_on_create, :proc ],
245 [ :after_validation_on_create, :object ],
246 [ :after_validation_on_create, :block ],
247 [ :before_save, :string ],
248 [ :before_save, :proc ],
249 [ :before_save, :object ],
250 [ :before_save, :block ],
251 [ :before_create, :string ],
252 [ :before_create, :proc ],
253 [ :before_create, :object ],
254 [ :before_create, :block ],
255 [ :after_create, :string ],
256 [ :after_create, :proc ],
257 [ :after_create, :object ],
258 [ :after_create, :block ],
259 [ :after_save, :string ],
260 [ :after_save, :proc ],
261 [ :after_save, :object ],
262 [ :after_save, :block ]
267 david
= CallbackDeveloper
.find(1)
270 [ :after_find, :string ],
271 [ :after_find, :proc ],
272 [ :after_find, :object ],
273 [ :after_find, :block ],
274 [ :after_initialize, :string ],
275 [ :after_initialize, :proc ],
276 [ :after_initialize, :object ],
277 [ :after_initialize, :block ],
278 [ :before_validation, :string ],
279 [ :before_validation, :proc ],
280 [ :before_validation, :object ],
281 [ :before_validation, :block ],
282 [ :before_validation_on_update, :string ],
283 [ :before_validation_on_update, :proc ],
284 [ :before_validation_on_update, :object ],
285 [ :before_validation_on_update, :block ],
286 [ :after_validation, :string ],
287 [ :after_validation, :proc ],
288 [ :after_validation, :object ],
289 [ :after_validation, :block ],
290 [ :after_validation_on_update, :string ],
291 [ :after_validation_on_update, :proc ],
292 [ :after_validation_on_update, :object ],
293 [ :after_validation_on_update, :block ],
294 [ :before_save, :string ],
295 [ :before_save, :proc ],
296 [ :before_save, :object ],
297 [ :before_save, :block ],
298 [ :before_update, :string ],
299 [ :before_update, :proc ],
300 [ :before_update, :object ],
301 [ :before_update, :block ],
302 [ :after_update, :string ],
303 [ :after_update, :proc ],
304 [ :after_update, :object ],
305 [ :after_update, :block ],
306 [ :after_save, :string ],
307 [ :after_save, :proc ],
308 [ :after_save, :object ],
309 [ :after_save, :block ]
314 david
= CallbackDeveloper
.find(1)
317 [ :after_find, :string ],
318 [ :after_find, :proc ],
319 [ :after_find, :object ],
320 [ :after_find, :block ],
321 [ :after_initialize, :string ],
322 [ :after_initialize, :proc ],
323 [ :after_initialize, :object ],
324 [ :after_initialize, :block ],
325 [ :before_destroy, :string ],
326 [ :before_destroy, :proc ],
327 [ :before_destroy, :object ],
328 [ :before_destroy, :block ],
329 [ :after_destroy, :string ],
330 [ :after_destroy, :proc ],
331 [ :after_destroy, :object ],
332 [ :after_destroy, :block ]
337 david
= CallbackDeveloper
.find(1)
338 CallbackDeveloper
.delete(david
.id
)
340 [ :after_find, :string ],
341 [ :after_find, :proc ],
342 [ :after_find, :object ],
343 [ :after_find, :block ],
344 [ :after_initialize, :string ],
345 [ :after_initialize, :proc ],
346 [ :after_initialize, :object ],
347 [ :after_initialize, :block ],
351 def test_before_save_returning_false
352 david
= ImmutableDeveloper
.find(1)
355 assert_raise(ActiveRecord
::RecordNotSaved) { david
.save
! }
357 david
= ImmutableDeveloper
.find(1)
358 david
.salary
= 10_000_000
361 assert_raise(ActiveRecord
::RecordInvalid) { david
.save
! }
363 someone
= CallbackCancellationDeveloper
.find(1)
364 someone
.cancel_before_save
= true
365 assert someone
.valid
?
367 assert_save_callbacks_not_called(someone
)
370 def test_before_create_returning_false
371 someone
= CallbackCancellationDeveloper
.new
372 someone
.cancel_before_create
= true
373 assert someone
.valid
?
375 assert_save_callbacks_not_called(someone
)
378 def test_before_update_returning_false
379 someone
= CallbackCancellationDeveloper
.find(1)
380 someone
.cancel_before_update
= true
381 assert someone
.valid
?
383 assert_save_callbacks_not_called(someone
)
386 def test_before_destroy_returning_false
387 david
= ImmutableDeveloper
.find(1)
388 assert
!david
.destroy
389 assert_not_nil ImmutableDeveloper
.find_by_id(1)
391 someone
= CallbackCancellationDeveloper
.find(1)
392 someone
.cancel_before_destroy
= true
393 assert
!someone
.destroy
394 assert
!someone
.after_destroy_called
397 def assert_save_callbacks_not_called(someone
)
398 assert
!someone
.after_save_called
399 assert
!someone
.after_create_called
400 assert
!someone
.after_update_called
402 private :assert_save_callbacks_not_called
404 def test_zzz_callback_returning_false
# must be run last since we modify CallbackDeveloper
405 david
= CallbackDeveloper
.find(1)
406 CallbackDeveloper
.before_validation proc
{ |model
| model
.history
<< [:before_validation, :returning_false]; return false }
407 CallbackDeveloper
.before_validation proc
{ |model
| model
.history
<< [:before_validation, :should_never_get_here] }
410 [ :after_find, :string ],
411 [ :after_find, :proc ],
412 [ :after_find, :object ],
413 [ :after_find, :block ],
414 [ :after_initialize, :string ],
415 [ :after_initialize, :proc ],
416 [ :after_initialize, :object ],
417 [ :after_initialize, :block ],
418 [ :before_validation, :string ],
419 [ :before_validation, :proc ],
420 [ :before_validation, :object ],
421 [ :before_validation, :block ],
422 [ :before_validation, :returning_false ]
426 def test_inheritence_of_callbacks
427 parent
= ParentDeveloper
.new
428 assert
!parent
.after_save_called
430 assert parent
.after_save_called
432 child
= ChildDeveloper
.new
433 assert
!child
.after_save_called
435 assert child
.after_save_called