ActiveRecord计数器缓存更新

时间:2014-04-04 21:00:59

标签: ruby-on-rails activerecord counter-cache

我遇到counter_cache的问题。说我有三个型号。用户和文章有很多ArticleUpvotes。用户可以为文章创建ArticleUpvote。

用户

# models/user.rb
class User < ActiveRecord::Base
  has_many :upvotes, class_name: 'ArticleUpvote'

  def upvote(article)
    article.upvotes.create(user: self)
  end
end

文章

# models/article.rb
class Article < ActiveRecord::Base
  has_many :upvotes, class_name: 'ArticleUpvote'
end

ArticleUpvote

# models/article_upvote.rb
class ArticleUpvote < ActiveRecord::Base
  include ArticleVote

  belongs_to :article, dependent: :destroy, counter_cache: :upvotes_count
end

# models/concerns/article_vote
module ArticleVote
  extend ActiveSupport::Concern

  included do
    belongs_to :user

    validates :user, presence: true
  end
end 

测试失败

context 'voting' do
  let(:user) { FactoryGirl.create(:user) }
  let(:article) { FactoryGirl.create(:article) }

  context '#upvote' do
    it 'adds upvote to article' do
      user.upvote(article)
      expect(article.upvotes.size).to eq 1
    end
  end
end

错误

1) User voting #upvote adds upvote to article
 Failure/Error: expect(article.upvotes.size).to eq 1

   expected: 1
        got: 0

   (compared using ==)

通过测试

只需将我的测试体更改为:

user.upvote(article)
article.upvotes.size # Added this line compared to failing version
expect(article.upvotes.size).to eq 1

或者这样做:

expect{ user.upvote(article) }.to change{ article.upvotes.size }.by 1

使测试通过。为什么会这样?

1 个答案:

答案 0 :(得分:1)

更改您的示例如下:

it 'adds upvote to article' do
  user.upvote(article)
  expect(article.reload.upvotes.size).to eq 1
end

您的给定示例失败的原因是规范持有使用article通过FactoryGirl创建的FactoryGirl.create(:article)对象,并且它不知道发生了更改数据库。您需要reload文章,以便反映变化。

在其他通过测试中,即

expect{ user.upvote(article) }.to change{ article.upvotes.size }.by 1 

您的示例已通过,因为change方法会发生隐式重新加载。