There are actually three choices when faced with this type of situation.
-
You can recognize that database integrity is more important than the principle of DRY, and create the straight-forward code and models.
-
You can recognize that database integrity is important, give up some clarity in your code, and use some not-so-obvious metaprogramming with your models to kinda maintain DRY.
-
You can believe that DRY is more important than the integrity of your data, and rely upon generic relations and Generic Foreign Keys (GFK).
(Note: I’m not going to address the potential performance implications of any of these options here. Performance-related issues are highly context-sensitive, and the real implications of these types of situations can only be evaluated in the context of the live deployment.)
<opinion>
Mentally, I put generic relations into the same category as signals. Frequently, they’re recommended and used in areas where they don’t belong or aren’t needed.
Yes, GFKs can be useful - but not in as many situations as people may think.
Yes, GFKs are sometimes even necessary.
But I would never refactor code to create GFKs, regardless of the amount of code that might be removed.
Our approach is always to consider a GFK as the “solution of last resort.” Our principle for schema design is more like “how can we avoid using a GFK here?” rather than “let’s use a GFK to make this easier.” (And yes, sometimes the answer is to use a GFK.)
</opinion>