Things you should know about Rails Active Record callback, an AOP in other language
2 min readNov 29, 2018
- Should avoid it when possible because its abstraction is not clear. The method such as
after_save
,before_save
…etc. don’t have a clear purpose of the business logic rather than CRUD. It applies whenever before or after save active record object. Even you have conditional callback, it will exist in model or tight coupling with model itself. It probably better to have service class to do the work which has clear purpose of the business logic. - If it is used it should be asynchronous, so that the main action like save or update request won’t rely on the the completion of the callback action. Use Sidekiq for example.
- Prefer
after_commit
toafter_save
,after_update
,after_destroy
because withafter_save
for example, the callback always execute no matter main action is execute successfully or not. Withafter_commit
withon:
option will tight with database transaction, this ensure that callback only execute when the transaction is complete. Another example using with asynchronous like Sidekiq dealing withid
because withoutafter_commit
sidekiq might pickupid
before object is committed to database. - On the other hand to point 1, I debate callback vs service class. Rails active record callback has its own value. For example, if
after_save: do_something
is a must in any circumstance, we should use call back because new developer might not be able to cover updo_something
in any adding new service class they create. More concrete example, if we want to destroy records in table A associated with table B when record in table B is changed, using callback might be a good option because if we have many service classes to trigger changing record in table A, we don’t need to modify all those service classes to destroy record in table A. If new developer create new interface or service class related to changing record in table B, they don’t have to know if they need to destroy record in table B because the callback in model say it all with test as well. However, if you are trying to use callback just in for specific logic rather than logic in model object, having service class is better option.
More best practice using callback in Rails: https://engineering.gusto.com/the-rails-callbacks-best-practices-used-at-gusto/