将关联从新对象转移到现有对象,同时防止创建新对象

时间:2014-01-29 22:28:28

标签: ruby-on-rails ruby rspec mongoid activemodel

版本

rails: (4.0.0)
ruby: (2.0.0)
mongoid (4.0.0)
activemodel (~> 4.0.0)
moped (~> 2.0.beta5)

问题

我有一个界面,我通过提交ISBN和作者列表来创建一本书。我的目的是避免重复的书籍记录,并确保我已经添加到具有特定ISBN的书籍的所有作者都被添加到原始书籍中,并且新书实际上并未创建。

我有一个类似于下面的书类,我写了一些测试,我也在下面列出。我认为这些测试对我的目的是正确的,但是如果他们没有测试我认为它们是什么,请赐教。

编辑:这些测试目前没有通过,所以我必须在某处做错事。测试是否写错了?

编辑2:我在规范中评论过,试图解释我面临的问题是什么。有几个失败的测试,我不明白究竟是什么错误。

编辑3:我删除了额外的规格,只保留了失败的规格

这不是实际问题,而是它的一般化版本。

书类

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

作者类

class Author
  include Mongoid::Document
  include Mongoid::Timestamps

  has_and_belongs_to_many :books

  field :name, type: String
end

模型rspec测试

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

1 个答案:

答案 0 :(得分:0)

在测试中尝试执行first_book.reload.authors以使其通过,只需在运行模型回调后重新加载以获取新作者。