存入controller后集成测试关联记录为nil
Associated record is nil in integration test after saving in controller
在控制器中,我有一个 update
方法,它创建一个记录(称为 book
),将其关联到现有记录(称为 author
)并保存它。
Book
属于一个Author
add_author_to_book_controller.rb
def update
@author = App::Models::Author.new(params)
@book = App::Models::Book.where(id: params[:book_id]).first
@book.author = @author
@book.save!
# this works fine...
# puts @book.author.inspect
render json: { status: :ok }
end
add_author_to_book_controller_spec.rb
describe App::AddAuthorToBookController do
describe '#update' do
# this is a contrived example, there is more setup regarding creating the "book" properly...
let(:name) { 'foobar' }
let(:action) { xhr :put, :update, params }
let(:params) { { first_name: name } }
subject { book }
before { action }
it { expect(response.status).to eq 200 }
it 'should save the author to the book' do
# why is author nil here?
# puts book.author.inspect
expect(book.author.first_name).to eq name
end
end
end
我在测试中尝试了 book.reload
,但没有成功。我是 rails 的新手,是否有一些传统的方法可以在控制器测试中测试关联记录?
首先我建议你让你的控制器更通用,因为这是你需要遵循的正确架构,所以你的控制器可以被称为 authors_controller.rb
并管理所有作者的东西或 books_controller.rb
并管理所有书籍的东西。按照这种方法,您可以有一个方法 associate_book
接收作者和一本书并创建正确的关联。让我用代码解释一下:
class Author < ApplicationRecord
has_many :books
# Fields :name
validates :name, presence: true
end
class Book < AoplicationRecord
# Optional because I think you want to add the author after create it
belongs_to :author, optional: true
# Fields :title, :publish_year, :author_id
validates :title, :publish_year, :author_id, presence: true
end
class AuthorsController < ApplicationController
def associate_book
# params here will contain the following [:author_id, book_id]
author = Author.find(params[:author_id])
book = Book.find(params[:book_id])
book.author = author
book.save!
rescue ActiveRecord::RecordInvalid => error
# This will allow you to catch exceptions related to the update
end
end
然后您可以通过执行以下操作来测试此方法,假设此方法将从路由中调用
# Testing with RSpec
# spec/controllers/authors_controller.rb
RSpec.describe AuthorsController do
let(:author) { Author.first }
let(:book) { Book.first }
it 'Should associate an author with a provided book' do
expect do
post :associate_book, params: { author_id: author.id, book_id: book.id }
end.to change { author.books.count }.by(1)
end
end
这将检查与作者关联的图书总数。
在将其关联到 book
之前未保存 author
...
def update
@author = App::Models::Author.new(params)
# was simply missing this
@author.save!
@book = App::Models::Book.where(id: params[:book_id]).first
@book.author = @author
@book.save!
# this works fine...
# puts @book.author.inspect
render json: { status: :ok }
end
在控制器中,我有一个 update
方法,它创建一个记录(称为 book
),将其关联到现有记录(称为 author
)并保存它。
Book
属于一个Author
add_author_to_book_controller.rb
def update
@author = App::Models::Author.new(params)
@book = App::Models::Book.where(id: params[:book_id]).first
@book.author = @author
@book.save!
# this works fine...
# puts @book.author.inspect
render json: { status: :ok }
end
add_author_to_book_controller_spec.rb
describe App::AddAuthorToBookController do
describe '#update' do
# this is a contrived example, there is more setup regarding creating the "book" properly...
let(:name) { 'foobar' }
let(:action) { xhr :put, :update, params }
let(:params) { { first_name: name } }
subject { book }
before { action }
it { expect(response.status).to eq 200 }
it 'should save the author to the book' do
# why is author nil here?
# puts book.author.inspect
expect(book.author.first_name).to eq name
end
end
end
我在测试中尝试了 book.reload
,但没有成功。我是 rails 的新手,是否有一些传统的方法可以在控制器测试中测试关联记录?
首先我建议你让你的控制器更通用,因为这是你需要遵循的正确架构,所以你的控制器可以被称为 authors_controller.rb
并管理所有作者的东西或 books_controller.rb
并管理所有书籍的东西。按照这种方法,您可以有一个方法 associate_book
接收作者和一本书并创建正确的关联。让我用代码解释一下:
class Author < ApplicationRecord
has_many :books
# Fields :name
validates :name, presence: true
end
class Book < AoplicationRecord
# Optional because I think you want to add the author after create it
belongs_to :author, optional: true
# Fields :title, :publish_year, :author_id
validates :title, :publish_year, :author_id, presence: true
end
class AuthorsController < ApplicationController
def associate_book
# params here will contain the following [:author_id, book_id]
author = Author.find(params[:author_id])
book = Book.find(params[:book_id])
book.author = author
book.save!
rescue ActiveRecord::RecordInvalid => error
# This will allow you to catch exceptions related to the update
end
end
然后您可以通过执行以下操作来测试此方法,假设此方法将从路由中调用
# Testing with RSpec
# spec/controllers/authors_controller.rb
RSpec.describe AuthorsController do
let(:author) { Author.first }
let(:book) { Book.first }
it 'Should associate an author with a provided book' do
expect do
post :associate_book, params: { author_id: author.id, book_id: book.id }
end.to change { author.books.count }.by(1)
end
end
这将检查与作者关联的图书总数。
在将其关联到 book
之前未保存 author
...
def update
@author = App::Models::Author.new(params)
# was simply missing this
@author.save!
@book = App::Models::Book.where(id: params[:book_id]).first
@book.author = @author
@book.save!
# this works fine...
# puts @book.author.inspect
render json: { status: :ok }
end