Conditional association

hello ,
i have an association as follows. A user is of type “author” or
“reader”.
In the user table is a column called user_type_id that references a
user_type table of 2 records, author, reader. What i am trying to do is
the
following:

Create an association such that a user has_one :profile, but the
:profile
is either author_profile table or reader_profile table (they have too
many
different attributes to make one profile table) depending on the user
type.
is there a way to specify a conditional has_one in the user model that
would allow access to ‘user.profile’ but know which model to reference ?
Either that or do a conditional set_table_name depending on a variable

Any help here appreciated.

Thanks
Adam

On 27 Jan 2008, at 03:58, AD wrote:

depending on the user type. is there a way to specify a conditional
has_one in the user model that would allow access to ‘user.profile’
but know which model to reference ? Either that or do a conditional
set_table_name depending on a variable …

Perhaps a polymorphic association ? Or alternatively use STI, and have
a base class User with the common functionality and both Author and
Read inheriting from that. Then it’s easy, because you just stick
has_one :author_profile in Author and has_one :reader_profile in Reader.

Fred

On Sun, Jan 27, 2008 at 10:29:06AM +0000, Frederick C. wrote:

has_one in the user model that would allow access to ‘user.profile’
but know which model to reference ? Either that or do a conditional
set_table_name depending on a variable …

Perhaps a polymorphic association ? Or alternatively use STI, and have
a base class User with the common functionality and both Author and
Read inheriting from that. Then it’s easy, because you just stick
has_one :author_profile in Author and has_one :reader_profile in Reader.

Yep, I was going to suggest STI. This is exactly the sort of situation
for
which it is appropriate.

Fred

Any help here appreciated.

Thanks
Adam
–Greg

On 1/27/08, Gregory S. [email protected] wrote:

(they have too many different attributes to make one profile table)
Yep, I was going to suggest STI. This is exactly the sort of situation for
which it is appropriate.

Well, it depends on how much the Author and Reader models have in
common, as to whether it makes sense to use STI, i.e. how many
attributes they have in common.

If it distorts reality too much to force them to use a single table,
then a polymorphic association is probably the better approach.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

You might want to add

attr_accessor :profile

to your User and then have the subclasses populate @profile on the
user instance as necessary. Off the top of my head you’d probably end
up with something like:

class User < Activerecord::Base
attr_accessor :profile
ene

class Reader < User
has_one :reader_profile
def profile
@profile ||= self.reader_profile
@profile
end
end

class Author < User
has_one :author_profile
def profile
@profile ||= self.author_profile
@profile
end
end

By doing something like that your view could simply work with
@user.profile without worrying about how to load the data. As for
rendering different templates, you should probably render only one,
and let that single template render the common components (User stuff)
and then farm out the custom stuff to partials.

HTH,
AndyV

I think the STI for the user model makes the most sense.
class User < Activerecord::Base

class Reader < User
has_one :reader_profile
end

class Author < User
has_one :author_profile
end

end

Assuming I had a common controller called profile and wanted to
display
the appropriate profile is there an easier way then

def show
case current_user.type
when ‘Reader’
@profile = ReaderProfile.find(:first, :conditions => ["user_id

?",current_user.id)
render :template => ‘reader_profile’
when ‘Author’
@profile = AuthorProfile.find(:first, :conditions => ["user_id

?",current_user.id)
render :template => ‘author_profile’
end
end

You can do something like this:

class Reader < User
has_one :profile, :class_name => ‘ReaderProfile’, :foreign_key
=> :reader_id
end

class Author < User
has_one :profile, :class_name => ‘AuthorProfile’, :foreign_key
=> :author_id
end

def show
render :template => current_user.profile.class.name.underscore
end