我如何验证记录已在 Rails 中创建?
How do i validate that a Record has been created in Rails?
我有一个小型 Rails 应用程序,其数据库包含不同的 Languages
。这些 Languages
中的每一个都可能发生变化,我想跟踪它们的变化。
我通过在对象更改时创建一个 Audit
记录来做到这一点。此 Audit
有一个验证关系的 has_many :languages, through: :audit_language_couplings
字段。
class Audit < ApplicationRecord
belongs_to :audit_type
has_many :audit_language_couplings
has_many :languages, through: :audit_language_couplings
validates_presence_of :audit_type, :admin_id, :date, :before
end
class Language < ApplicationRecord
has_many :audit_language_couplings
has_many :audits, through: :audit_language_couplings
validates_presence_of :iso_code, :display_name, :keyboard_layout, :flag_url, :luis_app_identification, :luis_authorized_key, :luis_location
end
当 PUT
、DELETE
或 POST
方法被调用时,通过调用 LanguagesController
中的 create_audit()
方法创建审计。我还有一个 /languages/:id/audits
端点 returns JSON 中给定语言的所有审核。
create_token()
方法:
def create_audit(type, admin_id)
@language.audits.create(
audit_type_id: type,
admin_id: admin_id,
date: Time.now.to_date,
before: @language.to_s # TODO: Use the to-be-created to_json() or to_s() method instead.
)
end
这也是我问题的本质(我认为)。
我目前正在使用 RSpec 和 Factory 机器人请求测试我的 API。当我在测试中创建或更新 Language
时,由于某种原因没有创建 Audits
。但我知道代码有效,因为当我在我的开发环境中用邮递员手动执行它时它有效。
FactoryBot.define do
factory :language do
iso_code { Faker::Address.country_code }
display_name { Faker::Address.country }
keyboard_layout { Faker::Internet.url }
flag_url { Faker::Internet.url }
luis_app_identification { Faker::Lorem.characters(5) }
luis_authorized_key { Faker::Lorem.characters(5) }
luis_location { Faker::Lorem.characters(5) }
end
end
我目前的测试结构如下:
describe 'POST /admin/language' do
let(:valid_attributes) do
{
payload: {
iso_code: 'en-US',
display_name: 'English (US)',
keyboard_layout: 'QWERTY',
flag_url: '/public/images/en-US.png',
luis_app_identification: 'test',
luis_authorized_key: 'test',
luis_location: 'test'
}
}
end
context 'when the request is valid' do
before { post '/admin/languages', params: valid_attributes, headers: token_header }
it 'creates a language' do
expect(json['iso_code']).to eq('en-US')
end
it 'returns status code 201' do
expect(response).to have_http_status(201)
end
context 'an audit should be made for the change' do
before { get "/admin/languages/#{language_id}/audits", headers: token_header }
it 'creates 1 audit' do
expect(json.size).to eq 1
end
it 'is an audit of type 1 [ADD]' do
expect(json[0]['audit_type_id']).to eq 1
end
end
end
context 'when the request is invalid' do
before do
post '/admin/languages', headers: token_header, params:
{
payload: {
display_name: 'English (US)',
keyboard_layout: 'QWERTY',
flag_url: '/public/images/en-US.png',
luis_app_identification: 'test',
luis_authorized_key: 'test',
luis_location: 'test'
}
}
end
it 'returns status code 422' do
expect(response).to have_http_status(422)
end
it 'returns a validation failure message' do
expect(response.body).to match(/Validation failed: Iso code can't be blank/)
end
end
end
我检查审计的测试失败了,因为当 运行 带有 RSpec 的代码时返回 0 个审计。
我想我对工厂做错了什么,但我不确定,请告诉我!
干杯
很难根据提供的代码准确说出发生了什么,但您可以尝试的一件事是将 create_audit
方法更改为:
def create_audit(type, admin_id)
@language.audits.create!(
如果由于某种原因创建失败,将 !
(bang) 添加到 create
方法将引发异常,这应该显示在您的 RSpec 日志中。这至少应该可以帮助您找到问题的根源。
你需要检查的是,当post发生时,Audit
实例的数量增加了一个。我会这样做:
subject { post '/admin/languages', params: valid_attributes, headers: token_header }
it 'creates an audit'
expect { subject }.to change { Audit.count }.by(1)
end
目前您通过间接方法(在第一个端点之后调用另一个 API 端点)测试是否存在一次审核(没有检查规范之前有多少)。
Pennycracker 和 ReggieB 的回答都是正确的,或者实际上是大局的一部分。
关于 create!()
shebang 的部分将我引向实际问题。工厂没有创建 Audit
所依赖的 AuditType
。
ReggieB 建议我的测试设置有缺陷,因为我正在测试嵌套请求。
我选择使用他的建议的修改版本,一个更适合我当前设置的版本:
context 'when the request is valid' do
before { post '/admin/languages', params: valid_attributes, headers: token_header(admin_id: admin.id) }
it 'returns status code 201' do
expect(response).to have_http_status(201)
end
context 'the audit system has to be updated' do
it 'creates 1 audit' do
expect(Audit.all.size).to eq(1)
end
it 'should have type 1 [ADD]' do
expect(Audit.first.audit_type.id).to eq(1)
end
end
end
数据库清理器 gem 在每个示例后清理数据库,因此检查第一个 Audit
与预期更改的工作方式相同。
感谢大家的帮助。
我有一个小型 Rails 应用程序,其数据库包含不同的 Languages
。这些 Languages
中的每一个都可能发生变化,我想跟踪它们的变化。
我通过在对象更改时创建一个 Audit
记录来做到这一点。此 Audit
有一个验证关系的 has_many :languages, through: :audit_language_couplings
字段。
class Audit < ApplicationRecord
belongs_to :audit_type
has_many :audit_language_couplings
has_many :languages, through: :audit_language_couplings
validates_presence_of :audit_type, :admin_id, :date, :before
end
class Language < ApplicationRecord
has_many :audit_language_couplings
has_many :audits, through: :audit_language_couplings
validates_presence_of :iso_code, :display_name, :keyboard_layout, :flag_url, :luis_app_identification, :luis_authorized_key, :luis_location
end
当 PUT
、DELETE
或 POST
方法被调用时,通过调用 LanguagesController
中的 create_audit()
方法创建审计。我还有一个 /languages/:id/audits
端点 returns JSON 中给定语言的所有审核。
create_token()
方法:
def create_audit(type, admin_id)
@language.audits.create(
audit_type_id: type,
admin_id: admin_id,
date: Time.now.to_date,
before: @language.to_s # TODO: Use the to-be-created to_json() or to_s() method instead.
)
end
这也是我问题的本质(我认为)。
我目前正在使用 RSpec 和 Factory 机器人请求测试我的 API。当我在测试中创建或更新 Language
时,由于某种原因没有创建 Audits
。但我知道代码有效,因为当我在我的开发环境中用邮递员手动执行它时它有效。
FactoryBot.define do
factory :language do
iso_code { Faker::Address.country_code }
display_name { Faker::Address.country }
keyboard_layout { Faker::Internet.url }
flag_url { Faker::Internet.url }
luis_app_identification { Faker::Lorem.characters(5) }
luis_authorized_key { Faker::Lorem.characters(5) }
luis_location { Faker::Lorem.characters(5) }
end
end
我目前的测试结构如下:
describe 'POST /admin/language' do
let(:valid_attributes) do
{
payload: {
iso_code: 'en-US',
display_name: 'English (US)',
keyboard_layout: 'QWERTY',
flag_url: '/public/images/en-US.png',
luis_app_identification: 'test',
luis_authorized_key: 'test',
luis_location: 'test'
}
}
end
context 'when the request is valid' do
before { post '/admin/languages', params: valid_attributes, headers: token_header }
it 'creates a language' do
expect(json['iso_code']).to eq('en-US')
end
it 'returns status code 201' do
expect(response).to have_http_status(201)
end
context 'an audit should be made for the change' do
before { get "/admin/languages/#{language_id}/audits", headers: token_header }
it 'creates 1 audit' do
expect(json.size).to eq 1
end
it 'is an audit of type 1 [ADD]' do
expect(json[0]['audit_type_id']).to eq 1
end
end
end
context 'when the request is invalid' do
before do
post '/admin/languages', headers: token_header, params:
{
payload: {
display_name: 'English (US)',
keyboard_layout: 'QWERTY',
flag_url: '/public/images/en-US.png',
luis_app_identification: 'test',
luis_authorized_key: 'test',
luis_location: 'test'
}
}
end
it 'returns status code 422' do
expect(response).to have_http_status(422)
end
it 'returns a validation failure message' do
expect(response.body).to match(/Validation failed: Iso code can't be blank/)
end
end
end
我检查审计的测试失败了,因为当 运行 带有 RSpec 的代码时返回 0 个审计。
我想我对工厂做错了什么,但我不确定,请告诉我!
干杯
很难根据提供的代码准确说出发生了什么,但您可以尝试的一件事是将 create_audit
方法更改为:
def create_audit(type, admin_id)
@language.audits.create!(
如果由于某种原因创建失败,将 !
(bang) 添加到 create
方法将引发异常,这应该显示在您的 RSpec 日志中。这至少应该可以帮助您找到问题的根源。
你需要检查的是,当post发生时,Audit
实例的数量增加了一个。我会这样做:
subject { post '/admin/languages', params: valid_attributes, headers: token_header }
it 'creates an audit'
expect { subject }.to change { Audit.count }.by(1)
end
目前您通过间接方法(在第一个端点之后调用另一个 API 端点)测试是否存在一次审核(没有检查规范之前有多少)。
Pennycracker 和 ReggieB 的回答都是正确的,或者实际上是大局的一部分。
关于 create!()
shebang 的部分将我引向实际问题。工厂没有创建 Audit
所依赖的 AuditType
。
ReggieB 建议我的测试设置有缺陷,因为我正在测试嵌套请求。
我选择使用他的建议的修改版本,一个更适合我当前设置的版本:
context 'when the request is valid' do
before { post '/admin/languages', params: valid_attributes, headers: token_header(admin_id: admin.id) }
it 'returns status code 201' do
expect(response).to have_http_status(201)
end
context 'the audit system has to be updated' do
it 'creates 1 audit' do
expect(Audit.all.size).to eq(1)
end
it 'should have type 1 [ADD]' do
expect(Audit.first.audit_type.id).to eq(1)
end
end
end
数据库清理器 gem 在每个示例后清理数据库,因此检查第一个 Audit
与预期更改的工作方式相同。
感谢大家的帮助。