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

http://ruby-doc.org/core/classes/Enumerable.html#M003140

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 http://github.com/rails/rails/commit/b763858ed5faeda720035dd2178e7c44aa34240a
(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