В прошлом у меня были похожие проблемы, которые решались путем перезагрузки ассоциации (а не родительского объекта).
Работает ли это, если вы перезагрузите thing.followers
в RSpec?
it "should have followers" do
@thing.followers.reload
@thing.followers.should == [@user]
end
РЕДАКТИРОВАТЬ
Если (как вы упомянули) у вас проблемы с обратными вызовами, которые не запускаются, вы можете выполнить перезагрузку в самом объекте:
class Thing < ActiveRecord::Base
after_save { followers.reload}
after_save :do_stuff
...
end
или
class Thing < ActiveRecord::Base
...
def do_stuff
followers.reload
...
end
end
Я не знаю, почему у RSpec есть проблемы с не перезагрузкой ассоциаций, но я сам сталкивался с такими же проблемами
Редактировать2
Несмотря на то, что @dantswain подтвердил, что followers.reload
помог решить некоторые проблемы, он все еще не решил их все.
Для этого решению потребовалось исправление от @kikuchiyo, которое требовало вызова save
после выполнения обратных вызовов в Thing
:
describe Thing do
before :each do
...
@user.things << @thing
@thing.run_callbacks(:save)
end
...
end
Окончательное предложение
Я полагаю, что это происходит из-за использования <<
в операции has_many_through
.Я не вижу, чтобы <<
фактически вообще вызывал ваше after_save
событие:
Ваш текущий код такой:
describe Thing do
before(:each) do
@user = User.create!(:name => "Fred")
@thing = Thing.create!(:name => "Foo")
@user.things << @thing
end
end
class Thing < ActiveRecord::Base
after_save :do_stuff
...
def do_stuff
followers.each { |f| puts "I'm followed by #{f.name}" }
end
end
, и проблема в том, что do_stuff
не вызывается.Я думаю, что это правильное поведение, хотя.
Давайте пройдемся по RSpec:
describe Thing do
before(:each) do
@user = User.create!(:name => "Fred")
# user is created and saved
@thing = Thing.create!(:name => "Foo")
# thing is created and saved
@user.things << @thing
# user_thing_relationship is created and saved
# no call is made to @user.save since nothing is updated on the user
end
end
Проблема состоит в том, что третий шаг фактически не требует восстановления объекта thing
- это просто создание записи в таблице соединения,
Если вы хотите убедиться, что @user делает вызов save, вы, вероятно, можете получить желаемый эффект, подобный следующему:
describe Thing do
before(:each) do
@thing = Thing.create!(:name => "Foo")
# thing is created and saved
@user = User.create!(:name => "Fred")
# user is created BUT NOT SAVED
@user.things << @thing
# user_thing_relationship is created and saved
# @user.save is also called as part of the addition
end
end
Вы также можете обнаружить, что after_save
фактически обратный вызов находится на неправильном объекте, и вы бы предпочли иметь его вместо объекта отношения.Наконец, если обратный вызов действительно принадлежит пользователю и вам нужно его запустить после создания отношения, вы можете использовать touch
для обновления пользователя при создании нового отношения.