rspec testando has_many: através de e depois de salvar

Eu tenho um (acho) relativamente simpleshas_many :through relacionamento com uma tabela de junção:

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

E esses testes rspec (sei que não são necessariamente bons testes, são apenas para ilustrar o que está acontecendo):

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

Isso funciona bem até eu adicionar umafter_save aoThing modelo que referencia seufollowers. Ou seja, se eu fizer

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

Em seguida, o segundo teste falha - ou seja, o relacionamento ainda é adicionado à tabela de junção, mas@thing.followers retorna uma matriz vazia. Além disso, essa parte do retorno de chamada nunca é chamada (como sefollowers está vazio no modelo). Se eu adicionar umputs "HI" no retorno de chamada antes dofollowers.each line, o "HI" aparece no stdout, então eu sei que o retorno de chamada está sendo chamado. Se eu comentar ofollowers.each linha, depois os testes passam novament

Se eu fizer isso em todo o console, ele funciona bem. Ou seja, eu posso fazer

>> 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]

Por que isso está falhando no rspec? Estou fazendo algo terrivelmente errado?

Atualiza

Tudo funciona se eu definir manualmenteThing#followers Com

def followers
  user_following_thing_relationships.all.map{ |r| r.user }
end

Isso me leva a acreditar que talvez eu esteja definindo meuhas_many :through com:source incorretamente?

Atualiza

Eu criei um projeto de exemplo mínimo e o coloquei no github:https: //github.com/dantswain/RspecHasMan

Outra Atualização

Obrigado a PeterNixey e @kikuchiyo pelas sugestões abaixo. A resposta final acabou sendo uma combinação das duas respostas e eu gostaria de poder dividir o crédito entre elas. Atualizei o projeto github com o que considero a solução mais limpa e realizei as alterações:https: //github.com/dantswain/RspecHasMan

Eu ainda adoraria se alguém me desse uma explicação realmente sólida sobre o que está acontecendo aqui. A parte mais preocupante para mim é por que, na declaração inicial do problema, tudo (exceto a operação do retorno de chamada) funcionaria se eu comentasse a referência afollowers.

questionAnswers(6)

yourAnswerToTheQuestion