Idea: call callbacks on self.type's model for existing instance, instead of current class when STI

Imagine you have Foo, SuperFoo < Foo, AlrightFoo < Foo (STI)
Additionally, you have a FooContainer that has_many :foos and accepts_nested_attributes_for :foos

You want to submit a PATCH request to the FooContainer controller, changing some fields on your container, but also changing the type of some of its children SuperFoo into AlrightFoo. Typically, I’d use @foo_container.update(foo_params) to update the container and its children.

So, granted you have a way to submit the type of Foo in your form with nested attributes, you can do this update and all works well. The container has been modified, the instance of SuperFoo has been mutated into an AlrightFoo, but the callbacks for AlrightFoo have not run!

If the child is a new child, then rails will create the Foo as an AlrightFoo, and any callbacks run were those of the AlrightFoo (as planned). If the child is an existing SuperFoo, then rails will create it (in my experience) as a Foo with this call, and won’t run the desired callbacks

I propose that, if you are changing the SuperFoo into an AlrightFoo, then you probably wanted the callbacks for the AlrightFoo to run, not those for the SuperFoo.

You could argue that:

I want the current class' callbacks to run
I want the new class' callbacks to run
I want both to run (?)

Perhaps this choice is something that could be exposed.

I feel that having a nice way to configure which callbacks will occur after a class mutation would be an excellent addition. From what I know, the current way to do this is to iterate over the children, call an update on each with that model’s specific params, cast them to the right model via becomes (or similar), then .save each one. I’d like to just do the container.update(nested_params)

It feels like this could be a pretty nice shortcut if implemented

Would love to hear thoughts on the matter, or patterns that make it feel less cumbersome to accept nested attributes for a STI class

Single table inheritance is generally a bad pattern, and leads to all kinds of nasty rabbit holes like the ones you are describing.

I generally avoid STI in almost all cases because of the overhead (it is generally not efficient from data base perspective) and all the callback woes you are describing are a good case in point for moving away from that style of programming entirely.