如何使用ShouldaMatchers测试此ActiveRecord关系?
class ViolatorUnitHistory < ActiveRecord::Base
...
belongs_to :primary_source, class_name: Source, primary_key: :source_1_id, foreign_key: :id
belongs_to :secondary_source, class_name: Source, primary_key: :source_2_id, foreign_key: :id
belongs_to :tertiary_source, class_name: Source, primary_key: :source_3_id, foreign_key: :id
...
end
class Source < ActiveRecord::Base
has_many :violator_unit_histories
end
describe "relationships" do
# Can't figure out this relationship
it { is_expected.to have_many(:violator_unit_histories).class_name('Source').with_primary_key('source_1_id').with_foreign_key('id') }
end
Failures:
1) Source relationships should have many violator_unit_histories class_name => Source
Failure/Error: it { is_expected.to have_many(:violator_unit_histories).class_name('Source').with_primary_key('source_1_id').with_foreign_key('id') }
Expected Source to have a has_many association called violator_unit_histories ()
# ./spec/models/source_spec.rb:17:in `block (3 levels) in <top (required)>'
it { is_expected.to have_many(:violator_unit_histories) }
Failures:
1) Source relationships should have many violator_unit_histories
Failure/Error: it { is_expected.to have_many(:violator_unit_histories) }
Expected Source to have a has_many association called violator_unit_histories (ViolatorUnitHistory does not have a source_id foreign key.)
我看到测试的belongs_to
方面发布了here的答案。但我似乎无法弄清has_many
这些更复杂的测试。
答案 0 :(得分:1)
首先,看起来您的主要/外键关系有点偏离。
从您的模型定义开始:
class ViolatorUnitHistory < ActiveRecord::Base
...
belongs_to :primary_source, class_name: Source, primary_key: :source_1_id, foreign_key: :id
belongs_to :secondary_source, class_name: Source, primary_key: :source_2_id, foreign_key: :id
belongs_to :tertiary_source, class_name: Source, primary_key: :source_3_id, foreign_key: :id
...
end
class Source < ActiveRecord::Base
has_many :violator_unit_histories
end
这里的问题是:id
似乎不是外键,而是主键。相反,source_1_id
似乎是ViolatorUnitHistory
模型上定义的外键。这是对的吗?
换句话说,假设您有Source
的关联violator_unit_histories
的实例,您希望@source.violator_unit_histories
返回什么?您的代码中没有任何内容可以清楚地定义violator_unit_histories
实际上是什么。
这就是您收到此错误的原因:
ViolatorUnitHistory没有source_id外键。
Rails正在source_id
类中查找ViolatorUnitHistory
外键,但是,其中一个不存在。
此外,在您的测试中,您没有明确定义测试subject
的内容。请考虑使用expect(<object>).to
语法使事情更加清晰。
答案 1 :(得分:1)
捎带Anthony E所说的,ViolatorUnitHistory =&gt;之间的关系。来源是明确定义的,但反之则不然。您可以说Violator.first.primary_source
,但由于数据库的规范化方式,Source.first.violator_unit_histories
不正确。
我可能会以与ViolatorUnitHistory =&gt;类似的方式定义每个反向关系。自ViolatorUnitHistory以来的源关系使用多个字段来存储Source.id
您可以添加以下内容:
class Source < ActiveRecord::Base
...
# I don't think primary_, secondary_ etc sources is a great name for these, since
# since it's really "History that has this as a primary source"
has_many :primary_sources, class_name: ViolatorUnitHistory, primary_key: :id, foreign_key: :source_1_id
has_many :secondary_sources, class_name: ViolatorUnitHistory, primary_key: :id, foreign_key: :source_2_id
has_many :tertiary_sourcs, class_name: ViolatorUnitHistory, primary_key: :id, foreign_key: :source_3_id
...
end
然后你的测试会变成:
describe "relationships" do
expect(source).to have_many :primary_sources
expect(source).to have_many :secondary_sources
expect(source).to have_many :tertiary_sources
end
另一种方法是规范化您的数据库,以便您有一个包含ViolatorUnitHistory.id
,Source.id
的连接表,以及一些常规指标(source_order或其他内容,适用于您的第1,第2,第3)< / p>
披露:我与Chris合作,我已经看到了实际的数据源,所以我对这个问题有了更多的了解