Has_many :through=>one

Hi everyone.

I am facing a problem with has_many :through with the following model
relations:

class User < AR
has_one :profile
has_many :files, :through => :profile
end

class Profile < AR
belongs_to :user
has_many :files
end

class File < AR
belongs_to :profile
end

While the call user.files succeeds with no problem, the following
assignment fails.

f = File.new
u = User.first
u.files << f # FAILURE HERE!

Rails spits out a
ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection
exception.

Can anyone shed some light on this ?

Cheers,

sergioL

On 12 January 2011 09:37, Sergio L. [email protected] wrote:

class Profile < AR
belongs_to :user
has_many :files
end

class File < AR
belongs_to :profile
end

I think you might want to reconsider using the name File as this is
already a class in Ruby. Whether this is the cause of your problem I
don’t know, but I would try that first.

Colin

On 12 January 2011 09:37, Sergio L. [email protected] wrote:

Can anyone shed some light on this ?

Exactly what the error says - you can’t have a has_many through a
has_one

Either chain the method calls to your user’s profiles files:

user = User.first
files = user.profile.files

…or create a delegate method in user to return the profile’s files:

class User < AR
has_one :profile
def files
self.profile ? self.profile.files : []
end
end

HTH

On 12 January 2011 09:47, Colin L. [email protected] wrote:

I think you might want to reconsider using the name File as this is
already a class in Ruby. Whether this is the cause of your problem I
don’t know, but I would try that first.

oh yeah… and try to avoid reserved words too :slight_smile:

On 12 January 2011 09:50, Michael P. [email protected] wrote:

…or create a delegate method in user to return the profile’s files:

class User < AR
has_one :profile
def files
self.profile ? self.profile.files : []
end
end

Or just put the profile data in the user table of course.

Colin

On 12 January 2011 10:14, Colin L. [email protected] wrote:

Or just put the profile data in the user table of course.

yebbut… encapsulation is a “good thing”… and you wouldn’t want
to encourage the OP to denormalise for the sake of it. It is nice to
have classes responsible for their own stuff. I like to keep the User
model of my own for just authentication/essential info, and delegate
addresses, telephones, hobbies, etc, to their own classes… horses
for courses :slight_smile:

On 12 January 2011 10:30, Michael P. [email protected] wrote:

On 12 January 2011 10:14, Colin L. [email protected] wrote:

Or just put the profile data in the user table of course.

yebbut… encapsulation is a “good thing”… and you wouldn’t want
to encourage the OP to denormalise for the sake of it. It is nice to
have classes responsible for their own stuff. I like to keep the User
model of my own for just authentication/essential info, and delegate
addresses, telephones, hobbies, etc, to their own classes… horses
for courses :slight_smile:

I agree about the encapsulation, it all depends on rest of the app
which way to go. However I don’t think your use of the word
denormalise is correct. The db would not be denormalised by moving
stuff into the user table. There would be no replication of data as
it is a has_one relationship. It would not be appropriate for things
such as hobbies which would likely be a habtm relationship.

Colin

On 12 January 2011 10:44, Colin L. [email protected] wrote:

However I don’t think your use of the word
denormalise is correct.

yeah… wrong term… sorry for any confusion. Encapsulation and
separation of responsibility is more the gist of why I’d keep the User
and Profile stuff apart. All personal preference and project
requirements decisions though…