using :through to get grandchildren objects

I cant seem to use :through to get the grandchildren objects when the intermedetiate uses a has_one relationship with the grandchild model.

E.g.

class User < ActiveRecord::Base   has_many :sentences   has_many :corrections, :through => :sentences end

class Sentence < ActiveRecord::Base   belongs_to :user   has_one :correction end

class Correction < ActiveRecord::Base   belongs_to :sentence end

I want to do User.corrections

but unfortunately that doesnt work. I get

ActiveRecord::HasManyThroughSourceAssociationMacroError: Invalid source reflection macro :has_one for has_many :corrections, :through => :sentences. Use :source to specify the source reflection.

but if i remove the has_one and replace it with has_many like so

class Sentence < ActiveRecord::Base   belongs_to :user   has_many :corrections #previously has_one end

then It works. The problem is I dont want to specify has_many because there will only be one correction for a sentence.

How do i achieve what I want, namely to be able to access all the corrections for a given user

Create a method on User called "corrections" and collect up the user's sentences' corrections.

  class User < ActiveRecord::Base     has_many :sentences

    def corrections       sentences.inject() { |memo, sentence| memo << sentence.corrections }.flatten.compact     end   end

Adam Akhtar wrote:

class Sentence < ActiveRecord::Base   belongs_to :user   has_many :corrections #previously has_one end

then It works. The problem is I dont want to specify has_many because there will only be one correction for a sentence.

So could you not use the has_many abilities of the framework (and achieve one of your goals) and enforce in your model your idea of a single correction per sentence (achieving your other goal)?

It might be the simplest solution.

Ar Chron wrote:

Adam Akhtar wrote:

class Sentence < ActiveRecord::Base   belongs_to :user   has_many :corrections #previously has_one end

then It works. The problem is I dont want to specify has_many because there will only be one correction for a sentence.

So could you not use the has_many abilities of the framework (and achieve one of your goals) and enforce in your model your idea of a single correction per sentence (achieving your other goal)?

It might be the simplest solution.

That's a pretty bad idea. has_one is a little smelly, but it's there, and it should work with :through. Better to solve the problem than to kludge around the framework.

Best,

thanks guys for the replies.

I considered Ars suggestion but for the same reason as Marnen posted it doesnt sit right.

But the problem is I created a new test project just to test the above syntax out and its failing. We all make mistakes and blame the framework but this time i honestly cant figure out the source of this problem. Im starting to think that this is simply not possible in rails when you have a has_one in the middle.

Can anyone confirm if this is a limitation of the framework?

Can anyone confirm if this is a limitation of the framework?

anyone???

You said in your first post that it *didn't* work trying to do a :though on a :has_one. So as far as I can see you have three choices:

  1) Fudge it with a :has_many that you manually check only has one associated - messy, as Marnen pointed out.

  2) Add the method I suggested to do the collect yourself (I default to using .inject, which is quite verbose... you could do the same thing with .map, which would remove the references to 'memo'). If the functionality *was* in Rails, it would be doing something similar in the background...

  3) Patch Rails yourself to support going through a :has_one - look at the source of :has_many and see what it's missing.

Personally, I'd do what I suggested (well, I would wouldn't I! :wink: as you can't expect the framework to do *everything* for you, and helpers like :through only come about when loads of people need to do the same thing frequently.

Adam Akhtar wrote:

Can anyone confirm if this is a limitation of the framework?

anyone???

How do you expect an answer to that if you haven't told us what versions of Ruby and Rails you're using?

Best,

I can confirm I get the same error trying to do a :has_many :through on a :has_one "grandchild" in Rails 2.3.5 and Ruby 1.8.7

Like I said, I don't think it's a "problem" - it's just not something that anyone's wanted enough (or at all) to be implemented. With the amount of time you've probably spent stressing about it, you could have written your own collection method a dozen times or more!

> Adam Akhtar wrote:

>>> Can anyone confirm if this is a limitation of the framework?

>> anyone???

> How do you expect an answer to that if you haven't told us what versions > of Ruby and Rails you're using?

I can confirm I get the same error trying to do a :has_many :through on a :has_one "grandchild" in Rails 2.3.5 and Ruby 1.8.7

Although this commit Enable has_many :through for going through a has_one association on t… · rails/rails@b763858 · GitHub (which would have made it into rails 2.3) claims otherwise

Fred

Hrmm.... I think curiosity will get me to check I wasn't running an old version... could've sworn the project I checked it on was 2.3.5... :-/

Marnen Laibow-Koser wrote:

Ar Chron wrote:

It might be the simplest solution.

That's a pretty bad idea. has_one is a little smelly, but it's there, and it should work with :through. Better to solve the problem than to kludge around the framework.

True, but I guess it depends on which 'smell' you find least disagreeable... hence the 'might be'.

If I had to have to working today, I'd work around the issue, and queue up the issue for analysis. If I had time to research, I'd dive into the framework code.

But that choice is very situational.

ahh sorry my bad. Im using rails 2.3.2 and ruby v1.87