代码之家  ›  专栏  ›  技术社区  ›  Igor Pantović

ActiveRecord计数器缓存更新

  •  0
  • Igor Pantović  · 技术社区  · 10 年前

    我有问题 counter_cache 。假设我有三个型号。用户和文章有许多ArticleUp投票。用户可以为文章创建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
    

    条款更新投票

    # 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 回复  |  直到 10 年前
        1
  •  1
  •   Kirti Thorat    10 年前

    更改示例如下:

    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 方法