如何根据 Rails 中的其他对象验证多对多关联?

Posted

技术标签:

【中文标题】如何根据 Rails 中的其他对象验证多对多关联?【英文标题】:How to validate many-to-many association based on other object in Rails? 【发布时间】:2021-12-26 20:30:27 【问题描述】:

注意:这是一个基于更复杂实现的简单示例。

考虑使用一个表单来提交租户详细信息,并使用一个子表单来添加公寓详细信息。仅当承租人声称年满 18 岁时才应创建公寓记录。

基于租户的一对一公寓验证

在之前的迭代中,这种关系是一对一的,并且 ID 存储在对象上。我能够根据租户信息验证公寓详细信息,如下所示:

class Apartment < ApplicationRecord
  validates :apartment_name, presence: true, if: lambda  |apartment|
    apartment.renter.try(:age) >= 18
  

该协会是直截了当的。但是,对于第三个连接表,可能不再存在链接。

基于租户的 N 对 N 公寓验证

在 lambda 中尝试 apartment.renters 会返回一个空的 CollectionProxy,我想这与预期的一样,因为尚未创建公寓记录并且无法将其添加到 Rentals 表中。

请务必注意,如果租户(17 岁以下)通过验证,则应创建/更新租户记录,并且不应创建公寓记录(未通过验证)。 公寓应该如何验证或以租用者对象为条件?这应该发生在控制器还是租用者模型中?

示例模型

class Apartment < ApplicationRecord
  has_many :rentals
  has_many :renters, through: :rentals
  accepts_nested_attributes_for :renters, allow_destroy: true
end

class Renter < ApplicationRecord
  has_many :rentals
  has_many :apartments, through: rentals
  accepts_nested_attributes_for :apartments, allow_destroy: true
end

class Rental < ApplicationRecord
  belongs_to :apartment
  belongs_to :renter
end

【问题讨论】:

我真的会将此建模为公寓有许多租赁协议,并且租赁协议中有许多租户(通过加入模型 - 也称为各方)。然后,您将验证租赁协议中至少有一个 18 岁以上的租户。您完全错过了难题的关键部分。 您可能实际上应该向我们询问您要解决的真正问题,即使它更复杂,因为您冒着问题的实际含义因过度抽象而在翻译中丢失的风险。 @max ty,我觉得这个例子是一个合适的替代品。我担心任何偏离这个概念的地方都可能会让人分心。您最初的评论正是为什么我将顶部注释作为阻止阅读对象并为业务逻辑提出建议的努力。希望专注于模型关系和验证标准所涉及的技术协调。要点:记录的验证/创建是相关模型的依赖值,该模型也在创建过程中。这更清楚吗?我可能没有充分描述问题。 这听起来不像是一个真正应该通过模型验证或嵌套属性来解决的问题,因为明显的问题 22。相反,您应该研究类似交互器模式的东西。 它更多的是一般模式。具有协调两个对象之间交互作用的对象。它早于 Rails。 【参考方案1】:

目前,我已经通过网络表单自然地处理验证错误,验证发生在 Renter 对象上。这不是对所提问题的真正解决方案,因为它推迟了创建 Renter 而不是应用程序的 big 条件——对我来说不公平。

这是一个简单、典型的验证(没有什么新东西),可以防止创建两个记录:

class Renter < ApplicationRecord
  has_many :rentals
  has_many :apartments, through: rentals
  accepts_nested_attributes_for :apartments, allow_destroy: true

  validates_each :apartments do |record, attr, value|
    record.errors.add(attr, 'must be at least 18') if record.age < 18
  end
end

如果我愿意接受这个解决方案或消除上述条件,我不会问这个问题。如果有人解决,我会选择一个更好的答案。

【讨论】:

以上是关于如何根据 Rails 中的其他对象验证多对多关联?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Rails 6中获取用户与朋友的多对多关联的created_at?

如何在 Rails 4.2 中为多对多关联创建表单

Rails 4 - best_in_place gem 和多对多关联

如何在 Rails 4 中为多对多关联制作带有子表单的表单?

在rails应用程序中使用Ransack搜索表单中的关联多对多关联

Rails Api 多对多如何发送和处理 json