Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord Callbacks List

I've been going through the rails source for a while now, and I don't think there's a better way of getting the list of all callbacks other than: ActiveRecord::Callbacks::CALLBACKS – which is a constant list.

Meaning if you're using a gem like devise_invitable that adds a new callback called :invitation_accepted with the score :after and :before then ActiveRecord::Callbacks::CALLBACKS will not work.

Do you know of an easy fix, other than opening up rails modules and making sure there's an internal list of call-backs per model class?

like image 295
Nima Gardideh Avatar asked Jul 17 '12 19:07

Nima Gardideh


People also ask

What are callbacks in Ruby?

Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it is possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.

Does Update_attributes call save?

Use update_attribute to skip validations. update_attribute uses save(false) while update_attributes uses save (which means save(true)). If perform_validation is false while calling save then it skips validation, and it also means that all the before_* callbacks associated with save.

What is Active Record in Ruby on Rails?

Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.


5 Answers

You can call Model._save_callbacks to get a list of all callbacks on save. You can then filter it down to what kind you need e.g. :before or :after like this:

Model._save_callbacks.select {|cb| cb.kind == :before}

Works the same for Model._destroy_callbacks etc.

like image 188
Sam Figueroa Avatar answered Oct 04 '22 17:10

Sam Figueroa


The docs say "There are nineteen callbacks in total"... but they don't seem to say what all of those 19 actually are!

For those who Googled "list of all ActiveRecord callbacks" like I did, here's the list (found by using ActiveRecord::Callbacks::CALLBACKS as described in the question):

:after_initialize
:after_find
:after_touch
:before_validation
:after_validation
:before_save
:around_save
:after_save
:before_create
:around_create
:after_create
:before_update
:around_update
:after_update
:before_destroy
:around_destroy
:after_destroy
:after_commit
:after_rollback
like image 45
GMA Avatar answered Oct 04 '22 19:10

GMA


Note that if you simply want to trigger callbacks, you can use the #run_callbacks(kind) method:

o = Order.find 123 # Created with SQL
o.run_callbacks(:create)
o.run_callbacks(:save)
o.run_callbacks(:commit)
like image 25
Duke Avatar answered Oct 04 '22 18:10

Duke


If you're working in a Rails version prior to the ._save_callbacks method, you can use the following:

# list of callback_chain methods that return a CallbackChain
Model.methods.select { |m| m.to_s.include? "callback" }.sort

# get all methods in specific call back chain, like after_save
Model.after_save_callback_chain.collect(&:method)
like image 32
Gray Kemmey Avatar answered Oct 04 '22 19:10

Gray Kemmey


I am going to propose most universal solution.

It works even when gems are declaring custom callbacks e.g. paranoia and after_real_destroy

To list all callbacks

Model.methods.select { |m| m.to_s.include? "callback" }.sort

Then you can get given callbacks if you type method name e.g.

Model._update_callbacks
Model._real_destroy_callbacks
Model._destroy_callbacks

If you list all callbacks, then you can find callback you need by checking @filter instance variable e.g.

require 'pp'
Activity._destroy_callbacks.each_with_index { |clbk,index| puts "#{index}-------\n#{clbk.pretty_inspect}" } ; nil 

# [...]

#<ActiveSupport::Callbacks::Callback:0x00007ff14ee7a968
 @chain_config=
  {:scope=>[:kind, :name],
   :terminator=>
    #<Proc:0x00007ff13fb825f8@/Users/mypc/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/activemodel-4.1.16/lib/active_model/callbacks.rb:103 (lambda)>,
   :skip_after_callbacks_if_terminated=>true},
 @filter=
  #<Proc:0x00007ff14ee7ac10@/Users/mypc/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/activerecord-4.1.16/lib/active_record/associations/builder/association.rb:135 (lambda)>,
 @if=[],
 @key=70337193825800,
 @kind=:before,
 @name=:destroy,
 @unless=[]>
4-------
#<ActiveSupport::Callbacks::Callback:0x00007ff14ee3a228
 @chain_config=
  {:scope=>[:kind, :name],
   :terminator=>
    #<Proc:0x00007ff13fb825f8@/Users/mypc/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/activemodel-4.1.16/lib/active_model/callbacks.rb:103 (lambda)>,
   :skip_after_callbacks_if_terminated=>true},
 @filter=:audit_destroy,
 @if=[],
 @key=:audit_destroy,
 @kind=:before,
 @name=:destroy,
 @unless=[]>
5-------
like image 26
nothing-special-here Avatar answered Oct 04 '22 19:10

nothing-special-here