Anyone who has built a transactional system has likely come across the challenge of maintaining historical state information while keeping their relationships up to date. For example: assume I have Widgets and Apparatuses and a Widget has a many to many relationship with Apparatus. I want to be able to change the price field of Widgets, but remember what the price was before (for my reporting purposes or any customer returns who bought widgets before and may want to return them, etc). We've always called this new-record-on-update system "sunsetting" records. There are several ways to handle this with varying degrees of elegance in the widget table - you could add a boolean Active column, and make us all cringe. A date range is somewhat better - if the date range is NULL you have your active entry, otherwise the date range corresponds to the time when that was active. Better still would be an independent universal ID that is maintained during edits (in addition to a date range so you know when the element was active).
But what of all your relationship tables? With this system every time you update Widget you'll also have to update all the records in Widgets_Apparatuses that used that old Widget key you are sunsetting. With lots of updates and lots of relationship tables this can get out of control pretty fast. So you think, "hey, I could just key this relationship in Widgets_Apparatuses to the widget_universal_id instead of the widget_id, then Widget can change all it wants and my relationship will always have the right widget. And with a modicum of SQL gymnastics to determine which widget record with this universal ID is the current one this method would work.
Unless you're trying to maintain ActiveRecord relationships or please your DBA friends. As written we can no longer say "widget.apparatuses" for the has_and_belongs_to_many (habtm) relationship we set up for them, since AR will be looking for a widget_id, not a universal_widget_id. I suspect there is probably a way to circumvent this, but no matter, there is a better way - breaking it out. What if instead of a universal_id on the widget table, we made that ID a foreign key from a new table? We could solve our other lookup problem while we were at it - New_table (say, Universal_Widget) could have a column "widget_id" which refers to the currently active widget_id. Universal_Widget is one way to look at it, though I prefer to call this one Widget, and call the old "Widget" becomes "Widget_Instance". The new Widget table's ID is our new universal_ID, and with a :has_one and reciprocal :belongs_to relationship in widget_instance we can maintain our foreign keys. Widget_Instance can hold onto all those changing properties that were in widget and we can sunset those records all we want without affecting our relationships.
But what if we actually needed to store historical data about those relationships? If we cared about which widgets were part of a particular apparatus last month, we won't be able to track that with this model. So what we really want is a model that allows us to sometimes sunset relationships - store last month's widgets_apparatuses - and sometimes not: don't redo all our widgets_apparatuses when you change the price of widgets. By now we have set up Apparatus_Instance the same way, and we see that by using this same Universal-Instantiation model for relationships we can solve our "sometimes" problem: the new table Widget_Instances_Apparatus_Instances. If we double up our relationships to exist at both the Widget level and the Widget_Instance level, we can maintain ActiveRecord's integrity and put the decision in the hands of the controller whether or not to generate new instances in the relationship table. Display logic is easy - just use Widgets_Apparatus when you want to list the widgets in the apparatus, and when reporting historical relationship data we can use some simple logic to bridge any gaps in Widget_Instances_Apparatus_Instances. Where Widget_Instance became a new record but we didn't re-set widget_instance.apparatuses, we pull down the relationship from widget_instance.widget.apparatuses. If we wanted to know what the widget.apparatuses were for a widget where they were not set, we could check to see what they were for last time they were set - by definition that was the last time we made a significant change. The reporting layer is the place we want to have to do our processing, so a little work here is fine. Note that this system is also going to require us to set properties by hand when we create new records... a new utility method that updates properties but not relationships will give us the control we want whereas a simple clone-adjust-save would update all those relationships.