should have_one(:item).through(:bla) doesn't work
Closed this issue · 7 comments
While have_many(:items).through(:bla)
is recognised by Shoulda, should have_one(:item).through(:bla)
doesn't seem to be implemented yet, it results in this error:
1) Item
Failure/Error: it { should have_one(:item).through(:bla) }
Expected Document to have a has_one association called activity (Item does not have any relationship to item)
It works for me. Your model is missing has_one :item
. That's what the failure tells me, at least.
However, if you can paste a failing test, I'll gladly re-open this. This is my spec: https://github.com/thoughtbot/shoulda-matchers/blob/master/spec/shoulda/active_record/association_matcher_spec.rb#L446-L469
Right, it was an error on my side, sorry for wasting your time.
But when we're just at it, here's another question: Why does Shoulda always insist on having the optional 2nd association also defined when checking on a :through relation?
# Works with Shoulda
has_one :document, :through => :activity_document
has_one :activity_document
# Doesn't with Shoulda, results in Expected Activity to have a has_one association called document (Activity does not have any relationship to activity_document)
has_one :document, :through => :activity_document
I asked a very similar question here about has_many :through. Thanks for explaining!
The second association is not optional, so far as I can tell. Here's a quick collection of models I made:
class Magazine < ActiveRecord::Base
has_one :document, :through => :activity_document
end
class Document < ActiveRecord::Base
belongs_to :activity_document
end
class ActivityDocument < ActiveRecord::Base
belongs_to :magazine
has_one :document
end
And here's what script/rails c
tells me:
irb(main):004:0> m = Magazine.create!
(0.0ms) begin transaction
SQL (0.3ms) INSERT INTO "magazines" ("created_at", "updated_at") VALUES (?, ?) [["created_at", Tue, 10 Jul 2012 13:05:08 UTC +00:00], ["updated_at", Tue, 10 Jul 2012 13:05:08 UTC +00:00]]
(2.7ms) commit transaction
=> #<Magazine id: 4, created_at: "2012-07-10 13:05:08", updated_at: "2012-07-10 13:05:08">
irb(main):005:0> m.document
ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :activity_document in model Magazine
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/reflection.rb:501:in `check_validity!'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations/association.rb:26:in `initialize'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations.rb:157:in `new'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations.rb:157:in `association'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations/builder/association.rb:44:in `document'
from (irb):42
Whereas adding the has_one :activity_document
to Magazine
fixes it.
Okay, maybe it's different to has_many :through? Because there the 2nd association is not needed, but Shoulda still insists on it. Why's that?
I asked a related question on StackOverflow.
Same problem with a has_many
:
class Magazine < ActiveRecord::Base
has_many :documents, :through => :activity_document
end
class Document < ActiveRecord::Base
belongs_to :activity_document
end
class ActivityDocument < ActiveRecord::Base
belongs_to :magazine
has_many :document
end
And similar output:
irb(main):007:0> m = Magazine.create!
(0.0ms) begin transaction
SQL (0.3ms) INSERT INTO "magazines" ("created_at", "updated_at") VALUES (?, ?) [["created_at", Tue, 10 Jul 2012 13:24:54 UTC +00:00], ["updated_at", Tue, 10 Jul 2012 13:24:54 UTC +00:00]]
(2.5ms) commit transaction
=> #<Magazine id: 3, created_at: "2012-07-10 13:24:54", updated_at: "2012-07-10 13:24:54">
irb(main):008:0> m.documents
ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :activity_documents in model Magazine
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/reflection.rb:501:in `check_validity!'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations/association.rb:26:in `initialize'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations/collection_association.rb:24:in `initialize'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations/has_many_through_association.rb:10:in `initialize'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations.rb:157:in `new'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations.rb:157:in `association'
from /var/lib/gems/1.8/gems/activerecord-3.2.6/lib/active_record/associations/builder/association.rb:44:in `documents'
from (irb):8
Please paste some code with an unexpected test failure/success next time.
Thanks,
-Mike
Strange, so why do people on StackOverflow tell me something different?
I tried it out myself now, and I got the same result like you (I'm sorry for not having tried it before and letting you do the work, I relied on the statements I was given on StackOverflow, let's see whether we can clarify this further there).
Okay, the people on StackOverflow didn't realize I was specifically asking about :through
, it seems. I have updated my question accordingly.