Do not change the behavior of the rails call_backs
- even if you knew how to, it makes it harder to work on the application later - change where you place the code.
You are getting too hung up on the names of the call_backs
. When they run is more important.
Here is what we know about your design without making the assumptions about which are the best ways of achieving it ...
- You have a method that runs after a new record is created
- You have a method that runs after a old record is updated
Here is where you seem to change your design decisions in order to make programming easier - but in doing so are breaking best practices ...
- For some reason you believe the method for updating should run every time (
after_save
) instead of after_update
)
- For some reason you believe the creation method should run after the method for updating (which is an unhealthy chaining of code)
Technically, the parts needed for both creating and updating should be divided out into a third method and called by both after_create
& after_update
so your code documents itself and is easier to understand.
All of this is relatively important - as most experienced programmers stress you should only utilize call_backs
when no other way is reasonable - due to the how hard they are to conceptualization in trouble shooting obscure problems.
Solution 1 - The Rails Way
after_save
should be used only for code that needs to run for both updates AND creations. Any code that needs to run for one or the other should be broken up in smaller methods & then called as needed by after_update
& after_create
to keep it DRY.
Solution 2 & 3 Refactoring old code without changing design
- Setup a working test to ensure your code fails and succeeds where you expect
after_save
has to run - so we know it has to be there. We wrap it in a method called 'update_method_code' to encapsulate it.
- Move the method definition for 'update_method_code' somewhere in model or service object.
- Leave the method call for 'update_method_code' in the
after_save
.
Since we didn't technically change anything the tests should be green.
- You code previously in
after_create
- wrap this in a method called 'new_object_code' so it's encapsulated.
- Move the method definition for 'new_object_code' somewhere in model or service object.
This is where you have a few choices ...
You can have 'update_method_code' test using one of the four
activerecord lifecycle checks to test call the method
'new_object_code'. This isn't good as it creates visibility issues
and means if one fails the rest fails. In a very heavy-handed way it
ensures your condition of 'new_object_code' only runs after
'update_method_code'
You use the already built Rails methods. after_save :update_method_code on: :create
to trigger the 'update_method_code'. See example here Rails Guide for transactions. Keep in mind here, this might run even if your other after_save
call does not ... so once again, this method is less sound than simply following the Rails Way & using after_update
/ after_create
.
Good luck with your project!
after_save
(or later) or drop using callbacks altogether. In favor of, for example, some kind of Builder pattern. – Sergio Tulentsevrails-3
torails-5
application upgrade. So changes as suggested by @SergioTulentsev are valid and preferable. – rayafter_create
logic intoafter_save
?after_save
will be run on updates also. – kanattibefore_create
. Something likeself.record_was_just_created = true
. Then check this flag inafter_save
. If flag is true, run the create-specific parts. Me, I would extract this into separate builder/updated objects. Should make the build procedure obvious. And avoidable, when needed. – Sergio Tulentsevnew_record?
. so in after_save call back checkself.new_record?
– Vishal