How to deal with one user-visible object stored as two logical objects

I'm not sure the Subject really captures what I'm trying to figure out how to do, so bear with me while I describe what I'm doing.

I've got two classes that I'm trying to figure out how best to structure. One of the classes contains data that is shared by 1 or more instances of the other class. However the user only ever sees the non-sharable class. A more concrete example might help... consider the case of a catalog of CDs. Each user has their own private catalog with a list of CDs. When the add a CD, not only do they add the CD instance to their collection, but they also create a shared CD_Info instance that other users are able to see. Most of the attributes of a user's CD are stored in the CD_Info instance, but a few (like purchase_price, and date_purchased, and was_gift?) are stored in the user's CD object. Also worth noting is that multiple user's CD objects can share a CD_Info instance... there's no point in duplicating all that data.

So there's a few things I'd like to do.

1) Whenever an object of type CD is retrieved from the database, the CD_Info object associated with it is loaded too. I know I can use the :include attribute, but I'd like to make that the default for loading instances of this type.

2) I want to create a form for adding an object of type CD and, since most of that metadata is stored in the CD_Info object, have those fields automatically routed there.

3) Find a CD object based on attributes of CD_Info.

4) Not have to update or add a bunch of helper functions in the CD class whenever I add another attribute to the CD_Info class.

Any suggestions would be very welcome. Thank you!

So I've been thinking about this more and I may have a solution to my
problem. I'm hoping people with more Rails experience than I have
might sanity-check this idea.

The point of the "shared" metadata is to avoid duplication of data,
partly to keep the DB smaller, but mostly to facilitate returning a
list of "potential matches" to users entering new data... they can
click a "Use This Data" (or some such) button and get all the fields
filled in, except for the ones that are related to their particular
instance (created_at, modified_at, etc.). It hit me this morning that
a self-referential table might be a better way to manage this (at
least within the context of a Rails app) than to separate tables. The
way it would work is to have a parent_id (or whatever its supposed to
be called for the Rails Magic to work) which, if non-nil, refers to
the instance with the metadata in it, and if nil, means that the
current instance has the metadata in it. I'd probably add a count of
how many children refer to each parent and use that to order the
"potential match" list returned to the user. This would only be
allowed to go 2 levels: parent and child.

I think this solution addresses two of the needs I mentioned before
(a single form that has all the fields necessary, and not having to
add a bunch of helper functions to make it look like the user's
object has all the same attributes as the shared object). I'm not
sure it handles automatic loading of the parent by default or finding
a child based on the attributes in the parent.

Am I off track here? Is there a better way to handle these issues?

Thanks!

Mark

From a database normalization point of view, take a look at this:

Class CdInfo (this would be the shared one, right?)   has_many :cds   has_many :tracks

  def name

Class Track   belongs_to :cd_info

  def sequence   def name

Class Cd   belongs_to :cd_info   belongs_to :user

Class User   had_many :cds

Cd contains foreign_keys cd_info_id and user_id Track contains foreign_key cd_info_id

dutchess_track_3 = User.find_by_id(whatever).cds.cd_info.find_by_name("The Duchess").tracks.find_by_sequence(3).name => "London Bridge"

Sorry if I've butchered the syntax. Still know SQL better than rails.

-Mack

That's basically what I'm starting with. Well, sorta (not bothering with the tracks just yet).

But what I'd like to be able to do is say

Cd.find_by_name("The Duchess")

and have rails know that the Name property is actually an attribute of the CDInfo object that each CD is required to have.

And also be able to say: <% form_for( :cd, :url => cd_path ) -%>     ... <% end -%> and have the fields for the CDInfo object show up there too.

My problem isn't so much with the DB and SQL as making sure I'm doing this in the Rails best-practice way. I'm sure others have had similar problems and it wouldn't surprise me if there's an elegant way of handling it (by passing some kind of parameter/flag to the belongs_to declaration or whatever). I just haven't been able to find such a way.

Mark

I see the similarities there. I'm just not sure that really captures the form use-case, as tags would be added one at a time, or a list of them all at once from a single form field... all the work is done in the controller. Also, since tags are a one to many mapping (one object having many tags), it doesn't address the ability to do a find on one object using fields in a related object it has a one to one mapping with.

Being able to use the "form_for( :cd, :url => cd_path )" construct is key to what I'm trying to accomplish. So far, I still haven't heard of any way to have a single form where you can specify fields that are in the object in the form_for() method *and* another object linked by that one. That's why I'm still thinking the self-referential way may be what I'm looking for... at least that way I get all the fields for the form, and only have to do a bit more work in the controller (which I assume I'd have to be doing anyway).

Mark