Обновление кеша ActiveRecord

98
5

У меня проблема с counter_cache. Скажем, у меня три модели. Пользователь и статья имеют много статей. Пользователь может создать 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

Делает тесты пройденными. Почему это происходит?

спросил(а) 2021-01-25T19:32:29+03:00 5 месяцев назад
1
Решение
63

Измените свой пример следующим образом:

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.

ответил(а) 2021-01-25T19:32:29+03:00 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема