In your test try doing first_book.reload.authors
to make it pass, it just needs to reload to pick up the new authors after you run your model callbacks.
transfer associations from new object to existing object while preventing creation of new object
-
04-10-2022 - |
Question
versions
rails: (4.0.0)
ruby: (2.0.0)
mongoid (4.0.0)
activemodel (~> 4.0.0)
moped (~> 2.0.beta5)
problem
I have an interface where I create a book by submitting an ISBN and a list of authors. My aim is to avoid duplicate book records, and to ensure that all the authors I've EVER added to a book with a specific ISBN get added to the original book, and that the new book does not actually get created.
I have a class that looks very similar to the book class below, and I've written some tests which I've also included below. I think the tests are correct for my purposes but please enlighten me if they're not testing what I think they are.
edit: These tests are not currently passing, so I must be doing something wrong somewhere. Are the tests written wrongly?
edit 2: I've commented in the specs to try to explain what the problems I'm facing are. There are a couple of failing tests and I don't understand what exactly is wrong.
edit 3: I've removed the extra specs, keeping only the specs that are failing
This is not the actual problem, but a generalised-ish version of it.
book class
class Book
include Mongoid::Document
include Mongoid::Timestamps
before_create :add_authors_to_existing_book_if_present
has_and_belongs_to_many :authors
field :isbn, type: String
validates_uniqueness_of :isbn
def add_authors_to_existing_book_if_present
if existing_book
existing_book.authors << self.authors
self.authors = []
existing_book.save!
# returns false to stop the model from
# being created if existing_book is truthy
false
end
end
def existing_book
Book.where(isbn: isbn).first
end
end
author class
class Author
include Mongoid::Document
include Mongoid::Timestamps
has_and_belongs_to_many :books
field :name, type: String
end
model rspec tests
describe "#add_authors_to_existing_book_if_present" do
context "when the book already exists in another author" do
let(:first_author) { Author.new(name: "First", books: [first_book]) }
let(:second_author) { Author.new(name: "Second", books: [second_book]) }
let(:first_book) { Book.new(isbn: "12345") }
let(:second_book) { Book.new(isbn: "12345") }
before do
first_author.save
second_author.save
end
# fails
it "only adds the first book to the second author" do
expect(second_author.books).to eq [first_book]
expect(second_author.books).not_to eq [second_book]
end
# this almost passes, but the author_ids in first_book is empty
# fails
it "assigns the second author to the first book" do
expect(first_book.authors).to eq [first_author, second_author]
end
# only the first_author is part of the array
end
end
Solution