Почему вы не используете FactoryBot associations
?
FactoryBot.define do
# tag factory with a `belongs_to` association for the book
factory :tag do
name { 'test_tag' }
book
trait :science do
name { 'science' }
end
end
# book factory with a `belongs_to` association for the author
factory :book do
title { "Through the Looking Glass" }
author
factory :science_book do
title { "Some science stuff" }
after(:create) do |book, evaluator|
create(:tag, :science, book: book)
end
end
end
# author factory without associated books
factory :author do
name { "John Doe" }
# author_with_science_books will create book data after the author has
# been created
factory :author_with_science_books do
# books_count is declared as an ignored attribute and available in
# attributes on the factory, as well as the callback via the evaluator
transient do
books_count { 5 }
end
# the after(:create) yields two values; the author instance itself and
# the evaluator, which stores all values from the factory, including
# ignored attributes; `create_list`'s second argument is the number of
# records to create and we make sure the author is associated properly
# to the book
after(:create) do |author, evaluator|
create_list(:science_book, evaluator.books_count, authors: [author])
end
end
end
end
Это позволяет вам:
create(:author).books.count # 0
create(:author_with_science_books).books.count # 5
create(:author_with_science_books, books_count: 15).books.count # 15
Таким образом, ваш тест становится:
RSpec.describe Author, type: :model do
describe '#has_science_tag?' do
let(:author_with_science_books) { create(:author_with_science_books, books_count: 1) }
context 'one science book' do
it 'returns true' do
expect(author_with_science_books.has_science_tag?).to eq true
end
end
end
end
И вы также можете рефакторинг Author#has_science_tag?
:
class Author < ApplicationRecord
has_many :books
def has_science_tag?
books.joins(:tags).where("tags.name ILIKE '%science%'").exists?
end
end