STI model; can you change the "type" column after creation to change the type of object?

If you create an activerecord object and save it, and it is a subclass of another model, and you are managing this with single table inheritance with a type column in the main table…

can you change the information in the “type” column to change the type of object?

i.e, type is “MediaMailOrder” and we just change it to “BulkMailOrder” and save it. We are having trouble with this.


Are you calling reload after you change the type?

(Your question led me to read about the becomes method in ActiveRecord, which I didn’t know of before, so thanks for that!)

Hi @andyw8. Yes, we are calling reload. Basically I set up a kind of STI situation for various kinds of orders Bulk, MediaMail, etc.

And sometimes when we find a MediaMail order passes address checking and can be sent as Bulk, I would change the type to Bulk (cheaper shipping).

And our tests in Rspec would change the type and save it, and then further down the order pipeline each type of order has its own “ship” method to ship itself based on what type it is.

But for some reason in production, when I change the type value it doesn’t save it. My developers I work with are saying this behavior is built into rails, but I haven’t seen anything really to back that up.

I found this article, and it does contain a workaround for that… But doesn’t necessarily seem like a safe / great solution to me.

I just want to report on what what causing us such a nightmare.

We would do @order.becomes!(MediaMailOrder).save

and at various times it would work, and at others not, and no real logic to it that we could find.

Eventually I found this post related to the paper_trail gem. The version of the gem we were using goes in and touches the type field on the model for some reason. When I disabled paper trail everything worked as expected. I think. I’m so tired I need to look at it again tomorrow. We spent quite a bit of time on this one. :frowning:

If we upgrade our paper_trail we should be okay.