On the last podcast, a reference was made to using super instead of callbacks.
Can someone post an example of how that works?
Thanks!
Don
On the last podcast, a reference was made to using super instead of callbacks.
Can someone post an example of how that works?
Thanks!
Don
The idea is that instead of:
class User < ActiveRecord::Base
after_save :do_something_after
end
You would do something like:
class User < ActiveRecord::Base
# override ActiveRecord::Base#save
def save
super
do_something_after
end
end
That would replicate the after_save callback by calling super
to do the save and then calling do_something_after
when thatâs done. You could call methods before super
to handle before_save
awesome⌠thanks!
Aside from the taboo of overriding âsaveâ, what does this approach achieve?
I feel like weâre not getting rid of callbacks, but rather re-implementing them.
To me, the main benefit is that it uses traditional inheritance over features provided by the base class to mimic inheritance. Less importantly, Itâs also immediately clear when looking at the class that save has some additional logic applied to it.
Why is overriding save taboo? Why would overriding an inherited method ever be taboo? Isnât that a problem?
Mmmm⌠I like it - makes the code feel more OOPish
Along this same line⌠is it kosher to do something like the following, and still expect to have the same return value as if you called save directly? If the calculate_total method somehow fails, would this method return false and have the same behavior (e.g. return with failed validations, etc) if you called save directly and had a failure?
def calculate_total_and_save
calculate_total && save
end
I vote for the callbacks - theyâre provided by Rails specifically for that purpose so you donât have to override their methods and possibly screw things up. Hooks like this are a time-honored way to provide safe injection of behavior into a package that you donât necessarily control - i.e.,
Iâm sure there are more reasons, so why would you start doing things in a non-standard way which you cannot use consistently and which doesnât provide the support that hooks do?
Yeah⌠possibly. Personally I havenât run into a lot of problems with callbacks, other than managing a bunch of conditional callbacks. However, there seems to be a lot of noise in the community lately arguing against using callbacks ever, unless theyâre dead simple.
I share your concern about ânon-standardâ methodologies, but it seems using super is usually explicit enough to avoid too much confusion.
Regardless, I think the improper use of callbacks (and ActiveRecord in general) has definitely contributed to the rise of the discussion around using so-called âService Objectsâ and âForm Objectsâ, etc.
Here are some of the resources that have âcoloredâ my view, fwiw
@JESii, just to play devilâs advocate, hereâs an answer to a few of your points.
what if the signature changes: you have to figure that out and go in and change it accordingly.
I think itâs pretty safe to say that initialize
, save
, create
, and the like are not going to change their signature. Your code would already be broken if it did. That said, calling super
handles signature changes pretty nicely.
the callbacks allow for selective action, using the on:, only: keys - the example above doesnât support thatâŚ
So I can only find three cases where this is applicable, before_validate
, after_validate
, and after_commit
. For the validation cases, Ruby provides if
which also allows for selective action. on: :create
becomes if new_record?
and so on. I do think that after_commit
is a case that canât be replaced with super
at the moment, if that is the case, it definitely wonât be the case for longer.
Also, remember that you shouldnât override initialize (Dale's Blog: Rails: Don't override initialize on ActiveRecord objects) ⌠I think this is still the caseâŚ
Youâre right, and thatâs something thatâs being worked on. As of Rails 4, I believe this is only the case for STI that itâs problematic.
And what about programmers who have to maintain your code when they are used to the callback hooks that almost every app uses?
Iâd make the point of what about programmers who have to maintain your app and are used to the way you handle this in Ruby? Itâs quite easy to follow that something happens on create when you see
def create
super
do_something_else
end
def create
super
do_something_else
end
if validation fails, does do_something_else
get called?