【发布时间】:2018-01-25 23:24:59
【问题描述】:
我有一个充当多对多关系的模型。类名是RelatedDocument,这是不言自明的,我基本上用它来关联Document类实例。
我遇到了验证问题,例如我在 RelatedDocument 类中有这个问题:
validates :document, presence: true, uniqueness: { scope: :related_document }
validates :related_document, presence: true
这项工作我无法创建重复的document_id/related_document_id 行。但是,如果我想从关系的另一端使其独一无二并将验证更改为:
validates :document, presence: true, uniqueness: { scope: :related_document }
validates :related_document, presence: true, uniqueness: { scope: :document }
这在另一边是不一样的。当我注意到这一点时,我正在编写 rspec 测试。如何编写验证或自定义验证方法来防止保存相同的 id 组合,无论它们来自哪一侧?
更新
根据评论部分的第一条评论,第一次唯一性验证将照顾双方,我说这不仅仅是因为我的 rspec 测试失败,它们是:
describe 'relation uniqueness' do
let!(:base_doc) { create(:document) }
let!(:another_doc) { create(:document) }
let!(:related_document) { described_class.create(document: another_doc, related_document: base_doc) }
it 'raises ActiveRecord::RecordInvalid, not allowing duplicate relation links' do
expect { described_class.create!(document: another_doc, related_document: base_doc) }
.to raise_error(ActiveRecord::RecordInvalid)
end
it 'raises ActiveRecord::RecordInvalid, not allowing duplicate relation links' do
expect { described_class.create!(document: base_doc, related_document: another_doc) }
.to raise_error(ActiveRecord::RecordInvalid)
end
end
第二次测试失败。
【问题讨论】:
-
您的第一个验证强制执行唯一的组合。您从哪个“方面”查看组合并不重要。因此,您不需要第二次验证。
-
@jvillian 但我的测试结果并非如此。在示例中,如果我有 doc1 和 doc2,如果我有
RelatedDocument.create!(document: doc1, related_document: doc2)会触发唯一性验证。然而,当我尝试RelatedDocument.create!(document: doc2, related_document: doc1)时,这并不是我想说的。第一次验证不考虑双方,至少在我的 rspec 测试中 -
噢噢噢噢!我懂了。您可以创建一个自定义验证来“从另一边”检查关系。这有一些二阶含义,您需要确保自己能够接受。
-
@jvillian 我尝试了类似
where(doc1 and doc2 OR doc2 and doc2).any?的方法,没有用,有什么想法吗? -
@rantingsonrails 的答案看起来很可靠。您是否想做类似:
@document_1.related_documents并取回所有相关文档 - 无论关系的“方向”如何?对于您当前的标题,这将非常棘手。
标签: ruby-on-rails ruby-on-rails-4 rspec