Polymorphism and brittle class names

I haven’t found an exact statement of this problem yet, but if you find one please direct me accordingly.

My one problem with polymorphic associations is that your code is now in the database. What happens when you rename a class, or re-scope it’s module?

Since class name changes are much more common than table name changes (citation needed), or at the very least you’re not in the DB layer of the world and may perhaps not think of it (whereas the inverse may be true), I think it makes sense to add an option to reference the polymorphic relationship by table.

E.g.

polymorphable_id

polymorphable_table # or polymorphable_table_name

I haven’t looked into how one would retrieve the class name from the table, but based on this SO post one would have to find a way to perhaps cache the model to table name. Models are all loaded anyway, so we could create a reverse-lookup.

Even with thousands of models, I don’t think this is unreasonable for the convenience, but I’m open to being wrong.

Thoughts?

1 Like

I think I answered my own Q. Looking at the “type” field for STI I forgot that models are not one-to-one mapped to tables, so we would have to deal with that too. So perhaps that’s the root issue. We’d have to provide explicit configuration for mapping classes to tables for every model that could be referenced in this manner. I guess that would be un-rails-like.

So perhaps the best we can do is make migration easier. Looks like there’s no way around just dealing with the DB layer once we open the “type”-like can of worms.

Wouldn’t the problem be solved by either 1. running a migration changing OldClassName to NewClassName, 2. doing OldClassName = NewClassName in app/models/old_class_name.rb?

I don’t follow. The column name isn’t OldClassName, so I’m not sure what that assignment is supposed to mean.

The issue is that a polymorphic reference can literally be any activerecord model in your app, there’s no restrictions. Really the only reliable way is to look at the DB and group by polymorphable_type to see which models you’ve referenced. You can’t know by looking at the code alone (unless you count looking at the code history too).

I’m confused. You said “What happens when you rename a class, or re-scope it’s module?” and I assumed you’re talking about renaming the class referenced by the _type column. Is this what you had in mind?