Abstracted associations?

I have a case where an association needs to be abstracted. It happens
to be a has_one.

The parent will always have a has_one association, but the exact
model/table that should point to will change based on value available
from the controller. So, it’s a parameter I can feed to
ParentModel.new()

I haven’t been able to find any references to doing that. Does Rails
allow for this, can it be hacked? Would Rails have a different
opinion as to how that need should be handled?

– gw

By an association that needs to be abstracted, do you mean a polymorphic
association?

– Josh

Greg W. wrote:

I have a case where an association needs to be abstracted. It happens
to be a has_one.

The parent will always have a has_one association, but the exact
model/table that should point to will change based on value available
from the controller. So, it’s a parameter I can feed to
ParentModel.new()

I haven’t been able to find any references to doing that. Does Rails
allow for this, can it be hacked? Would Rails have a different
opinion as to how that need should be handled?

– gw

allow for this, can it be hacked? Would Rails have a different
opinion as to how that need should be handled?

On Jun 11, 2008, at 4:08 PM, Joshua A. wrote:

By an association that needs to be abstracted, do you mean a
polymorphic
association?

Hmm. Dunno. Will read up on that, but meanhwile, what I’m doing is
something akin to this:

class Vehicle < AR::Base
has_one :engine
end

class Engine < AR::Base
belongs_to :vehicle
end

But… I need Engine to be JetEngine, TurboFanEngine, PistonEngine –
all engines, but with completely different attributes from each other.

So, yes, generically, this could be polymorphic classes. Outside of
AR CRUD, they’ll have little in common. It remains to be seen how
many class-specific methods each might have.

So, yeah, I’m trying to figure out where Rails wants to handle this–
inside Vehicle, or inside Engine.

– gw

For what you’re saying, it doesn’t really sound like you’re looking for
polymorphism. Polymorphism would be where you have an object that can
belong to many different objects. (Like Comment could be associated to a
BlogPost, an Article, a Message, etc).

It sounds like you’re looking for STI. So you would define your base
class Engine, and subclass the other *Engine classes out of that. Shared
methods could simply be placed in the Engine model, making those methods
available to it’s subclasses, and then a method specific to JetEngine
only could be put in the JetEngine class.

This page is helpful with how STI would work:
http://wiki.rubyonrails.org/rails/pages/singletableinheritance

– Josh

Greg W. wrote:

allow for this, can it be hacked? Would Rails have a different
opinion as to how that need should be handled?

On Jun 11, 2008, at 4:08 PM, Joshua A. wrote:

By an association that needs to be abstracted, do you mean a
polymorphic
association?

Hmm. Dunno. Will read up on that, but meanhwile, what I’m doing is
something akin to this:

class Vehicle < AR::Base
has_one :engine
end

class Engine < AR::Base
belongs_to :vehicle
end

But… I need Engine to be JetEngine, TurboFanEngine, PistonEngine –
all engines, but with completely different attributes from each other.

So, yes, generically, this could be polymorphic classes. Outside of
AR CRUD, they’ll have little in common. It remains to be seen how
many class-specific methods each might have.

So, yeah, I’m trying to figure out where Rails wants to handle this–
inside Vehicle, or inside Engine.

– gw

Greg W. wrote:

opinion
end
inside Vehicle, or inside Engine.
Joshua A. wrote:
It sounds like you’re looking for STI.

Mmm. I don’t believe so. The data are completely different for each
engine class. In cases where there’s a lot of similar data and a few
fields exclusive to each “type” then, I’m willing to bunch them
together in a shared table and derive records/classes by type field,
but for this case, the tables share very few fields and should be
independent.

– gw

On Jun 12, 2:59 am, Greg W. [email protected] wrote:

Mmm. I don’t believe so. The data are completely different for each
engine class. In cases where there’s a lot of similar data and a few
fields exclusive to each “type” then, I’m willing to bunch them
together in a shared table and derive records/classes by type field,
but for this case, the tables share very few fields and should be
independent.

I assume more than one vehicle could have the same engine, so did you
mean
class Vehicle < AR::Base
belongs_to :engine
end

class Engine < AR::Base
has_one :vehicle
end

if so, then a polymorpic association could do the trick: then change
the belongs_to to belongs_to :engine, :polymorphic => true
and the has_one to has_one vehicle, :as => :engine.

Then when you to foo.engine = some_jet_engine then engine_id will be
be set appropriately and engine_type will be set to JetEngine

Fred

Once again–what Fred said. :wink: Look into polymorphic associations. If
I understand it right, you put profile_id and profile_type fields in
your users table. profile_type is what tells AR which table to go to
for a given user’s profile.

On Jun 12, 2008, at 12:46 AM, Frederick C. wrote:

On Jun 12, 2:59 am, Greg W. [email protected] wrote:

Mmm. I don’t believe so. The data are completely different for each
engine class. In cases where there’s a lot of similar data and a few
fields exclusive to each “type” then, I’m willing to bunch them
together in a shared table and derive records/classes by type field,
but for this case, the tables share very few fields and should be
independent.

I assume more than one vehicle could have the same engine,

In this case, no. At least, not how I interpret the question. I guess
I’ll just spell it out (at the risk of invoking sidebar questions).

PrivilegedUser (authentication details only)
has_one profile
has_many privileges
has_many filters

Profile (remainder of a user’s “description”)
(set_table_name = x or y or z)
belongs_to privileged_user

Privilege (1 record per privilege)
belongs_to privileged_user

Filter (1 record per data access filter definition)
belongs_to privileged_user

Any one PrivilegedUser table record will be associated with one, and
only one, of the Profile tables, and only one record in that Profile
table. Any entry in the Profile table will be associated with one,
and only one, of the PrivilegedUser table records. At any one time
there is only ever one instance of a PrivilegedUser being used per
request – that being the logged in user.

This is for a group of applications where some of them have multiple
user models in which profile details for one type of user is very
different than another. Simple apps will need only one Profile,
complex apps can have several. Profile tables could have a handful of
fields or dozens of fields–of which none may be common, so it just
doesn’t make sense to use a single table. (Think doctors & patients,
teachers & students – both sharing the same login system, but vastly
different user profiles because they use the app in very different
ways).

I have used this system for quite some time already. The methodology
is sound (and it’s 90% written in Rails already), I’m just trying to
figure out how to Railsify this and one other implementation detail.

At first I was wondering whether to try to handle it in
PrivilegedUser or Profile, but the more I think about it, if it is
possible to parameterize the has_one declaration in PrivilegedUser, I
think that’s what I’m looking for (which is how I handled it before),
and I’ll end up with a unique model per specific Profile (probably
sub-classed ones, so I can consolidate common methods).

– gw