【发布时间】:2018-12-03 16:17:02
【问题描述】:
我有一个小型 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 端点,它以 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 bot 请求测试我的 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方法在哪里调用?你能显示控制器代码吗? -
您可以做的一件事来解决问题是将您的 create_audit 方法更改为执行
@language.audits.create!(。这样,如果创建失败,您将在 RSpec 中看到错误。 -
为什么您认为这里需要审计和语言之间的多对多关联?我认为它实际上是一对多(审计
belongs_to :language和语言has_many :audits),因为您正在跟踪对单个记录的更改。 -
好像你没有设置
language_id。 -
谢谢 Pennypacker,我想我找到了问题所在,看来我的种子没有在启动时运行。因为它警告我在数据库中缺少 AuditType。我希望以前有人告诉过我这个把戏。我将尝试解决此问题并报告。最大,因为还有其他对象使用
Audit,所以我的想法是审核不需要有Language或Answer或任何其他记录。不确定我的火车在这里是否正确。
标签: ruby-on-rails ruby validation rails-activerecord