0

Lets say I have the following class

class Foo < ActiveRecord::Base

before_save :before_callback_1, :before_callback_2, :before_callback_3
after_save :after_callback_1, :after_callback_2, :after_callback_3

end

I want to do something like:

foo = Foo.new

foo.run_before_save_callbacks
foo.update_columns(...)
foo.run_after_save_callbacks

Is there some active record method that allows me to do this or do I need to get a list of all the callbacks and filter them and run them manually?

  • It seems to me that this question has the answer that you're looking for: https://stackoverflow.com/questions/632742/how-can-i-avoid-running-activerecord-callbacks. What do you think? – Pedro Paiva Aug 03 '22 at 21:43
  • @PedroPaiva unfortunately that question is about not invoking callbacks, my question is about manually invoking them – New To Blue Aug 04 '22 at 03:10
  • 2
    Why do you want to run the before and after callbacks manually instead of using `update` that would trigger those callbacks automatically? – spickermann Aug 04 '22 at 06:55
  • @spickermann it appears that trying to simplify my example by using update_columns has actually caused more confusion since everyone is fixating on that instead of the actual root of the question. In my real world example I am using insert_all since there are thousands of records that I insert at a time that have callbacks that need to be executed so I'm trying to manually execute all the before callbacks on each record, insert all, then run all the after callbacks – New To Blue Aug 04 '22 at 21:01

3 Answers3

2

You can trigger calling before_save and after_save callbacks like this:

foo.run_callbacks(:save) { foo.update_columns(...) }

See ActiveSupport::Callbacks.

spickermann
  • 100,941
  • 9
  • 101
  • 131
0

Instead of update_columns use update (or the alias update_attributes) to accomplish the update while also running callbacks. It would take the place of your 3 lines there.

#foo.run_before_save_callbacks # No need, already run by `update`.
foo.update(...)
#foo.run_after_save_callbacks  # No need, already run by `update`.
BenFenner
  • 982
  • 1
  • 6
  • 12
0

After reading your comment replies I have a better idea of what you're looking for. At the least, if you want to run before_save callbacks manually, you can get a list of them like this:

callbacks    = Foo._save_callbacks.select{ |callback| callback.kind == :before }
method_names = callbacks.map(&:filter)

Similarly for after_save callbacks:

callbacks    = Foo._save_callbacks.select{ |callback| callback.kind == :after }
method_names = callbacks.map(&:filter)

(I actually use this in minitest to make sure our models have the expected callbacks.)

BenFenner
  • 982
  • 1
  • 6
  • 12
  • Thanks! It looks like manually getting the callbacks and running them myself is what I need to do as there is no built in rails method to do it unfortunately – New To Blue Aug 04 '22 at 20:58
  • Please keep in mind, `has_many :models, dependent: :null` will create `after_destroy` callbacks. Not sure about other callbacks like `after_save`. Just something to be aware, especially if you are planning on calling them manually – kbrock Aug 22 '23 at 16:42