我has_many :through
与连接表有(我认为)相对简单的关系:
class User < ActiveRecord::Base
has_many :user_following_thing_relationships
has_many :things, :through => :user_following_thing_relationships
end
class Thing < ActiveRecord::Base
has_many :user_following_thing_relationships
has_many :followers, :through => :user_following_thing_relationships, :source => :user
end
class UserFollowingThingRelationship < ActiveRecord::Base
belongs_to :thing
belongs_to :user
end
还有这些 rspec 测试(我知道这些不一定是好的测试,这些只是为了说明正在发生的事情):
describe Thing do
before(:each) do
@user = User.create!(:name => "Fred")
@thing = Thing.create!(:name => "Foo")
@user.things << @thing
end
it "should have created a relationship" do
UserFollowingThingRelationship.first.user.should == @user
UserFollowingThingRelationship.first.thing.should == @thing
end
it "should have followers" do
@thing.followers.should == [@user]
end
end
这工作正常,直到我将一个添加after_save
到Thing
引用其followers
. 也就是说,如果我这样做
class Thing < ActiveRecord::Base
after_save :do_stuff
has_many :user_following_thing_relationships
has_many :followers, :through => :user_following_thing_relationships, :source => :user
def do_stuff
followers.each { |f| puts "I'm followed by #{f.name}" }
end
end
然后第二个测试失败 - 即关系仍然添加到连接表,但@thing.followers
返回一个空数组。此外,回调的那部分永远不会被调用(好像followers
在模型中是空的)。如果我puts "HI"
在该行之前的回调中添加一个followers.each
,则“HI”会显示在标准输出上,所以我知道正在调用回调。如果我注释掉该followers.each
行,那么测试将再次通过。
如果我通过控制台完成这一切,它工作正常。即,我可以
>> t = Thing.create!(:name => "Foo")
>> t.followers # []
>> u = User.create!(:name => "Bar")
>> u.things << t
>> t.followers # [u]
>> t.save # just to be super duper sure that the callback is triggered
>> t.followers # still [u]
为什么这在 rspec 中失败了?我做错了什么可怕的事情吗?
更新
如果我手动定义Thing#followers
为,一切正常
def followers
user_following_thing_relationships.all.map{ |r| r.user }
end
这使我相信也许我错误地定义了我has_many :through
的:source
?
更新
我创建了一个最小的示例项目并将其放在 github 上:https ://github.com/dantswain/RspecHasMany
另一个更新
非常感谢@PeterNixey 和@kikuchiyo 在下面提出的建议。最终的答案原来是两个答案的组合,我希望我可以在它们之间分配功劳。我已经用我认为最干净的解决方案更新了 github 项目并推送了更改:https ://github.com/dantswain/RspecHasMany
如果有人能给我一个关于这里发生的事情的真正可靠的解释,我仍然会喜欢它。对我来说最麻烦的是为什么在最初的问题陈述中,如果我注释掉对followers
.