Callbacks are methods that get called at certain moments of an object’s life cycle. If you’re wondering why the above sentence sounds so coherent, its because I stole it verbatim from the Rails Guides.
So most people are pretty familiar with before and after callbacks. before_save and after_update pretty much explains itself. There is another type of callback though, called around.
What in the world does it do?
What it does is it allows you to run code both before and after an operation. So an example will be like this:
class Facility < ActiveRecord::Base around_save :method_around_save private def method_around_save # you can do stuff here yield <---- the save happens here # you can continue doing stuff here as well end end
So why is this useful? Whats the difference between this and doing 2 separate before_save and after_save callbacks?
In my opinion, the around callback could be useful if you want all your database transactions in your callbacks to be atomic.
Or if you want whatever you’re doing in after_save depends on what happens before_save
Lets have a concrete example, based on a make-believe real life scenario
Say you have a Building model, which has a number of facilities under it.
Every time a building is created, you want to create a set number of hardcoded facilities.
class Building < ActiveRecord::Base has_many :facilities after_create :create_facilities def create_facilities #Do facility creation here end end
So each facility, will have a number of sub-facilities (Just like how badminton courts have Court A, Court B, etc). These sub-facilities are also created when the a facility is created
class Facility < ActiveRecord::Base after_create :create_subfacilities def create_subfacilities # sub-facilities will be created here. end end
So this looks ok, I guess. But what if someone updates the facility? Maybe the user made a mistake and set the number of sub-facilities to 2 when actually there were 3 sub-facilities?
One way is to do a check before the update happens to see if the number of sub-facilities has changed (before_update) and then update the sub-facilities after the facility has been updated (after_update)
Something like this maybe?
class Facility < ActiveRecord::Base after_create :create_subfacilities before_update :check_for_subfacility_change after_update :sync_subfacility def check_for_subfacility_change @sync? = true if #subfacility has been changed end def sync_subfacility #update number of sub-facilities based on the value of @sync? end def create_subfacilities # sub-facilities will be created here. end end
I’m just guessing here, but perhaps this could be a bit difficult to read after a few months and when the class gets bigger. So it could be easier if we did the whole thing in one around_update callback.
Perhaps something like this
class Facility < ActiveRecord::Base after_create :create_subfacilities around_update :sync_subfacility def sync_subfacility sync? = true if #subfacility has been changed yield #update sub-facilities if sync? is true end def create_subfacilities # sub-facilities will be created here. end end
So there you go, hopefully that made sense. If you can think of a better way please reply in the comments