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 Willits wrote:

Greg Willits 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?

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 Willits wrote:

Greg Willits 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?

What I am doing is 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, I'm trying to figure out where Rails wants to handle this--
inside Vehicle, or inside Engine.

Joshua Abbott 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

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

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

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.