【问题标题】:Limiting has_one relationships in Rails在 Rails 中限制 has_one 关系
【发布时间】:2016-01-04 22:52:27
【问题描述】:

我有两个这样的 ActiveRecord 模型:

class User < ActiveRecord::Base
  has_one :contact_information
end

class ContactInformation < ActiveRecord::Base
  belongs_to :user
end

这是我在用户和联系信息表之间建立一对一关系的设置。

我遇到的问题是,当我创建一个新的contact_information 条目,该条目指向一个已经有一个现有contact_information 的用户时,会创建包括关系在内的新记录,这意味着我有两个contact_information 记录指向同一个用户,甚至虽然是一对一的关系。

Rails 似乎选择了第一条记录并将其返回。

例如在irb中:

> User.create
> ContactInformation.create(user: User.last)
> ContactInformation.create(user: User.last)
> ContactInformation.all
=> #<ActiveRecord::Relation [#<ContactInformation id: 3, created_at: "2016-01-04 22:28:11", updated_at: "2016-01-04 22:28:11", user_id: 2>, #<ContactInformation id: 4, created_at: "2016-01-04 22:28:18", updated_at: "2016-01-04 22:28:18", user_id: 2>]>

两者都将 user_id 设置为 2。

理想的情况是在为已有contact_information 的用户创建记录时,contact_information 的验证失败。

我为联系人信息模型提出了这种初始自定义验证方法,该方法适用于创建(需要制作一个以进行更新)

validate :check_parent, on: :create

def check_parent
    if user.contact_information.id.nil?
        errors.add(:user, "already has contact information")
    end
end

我想知道是否有更多的 rails-y 方法来解决这个问题?或者我是否需要为所有 has_one 关系创建一个这样的自定义验证器?

谢谢

【问题讨论】:

  • 我认为如果您改为使用user.contact_info=ContactInfo.create(),它将取消链接先前链接并替换它。不确定你是否想要,因为现在你有一个孤立的ContactInfo。您可以编辑现有的,而不是替换它或添加一个新的?或者换句话说:这个问题的用例是什么?例如。在一个表单中,我总是将has_one 显示为所有者的额外字段。或者我会允许存在多个联系信息(为什么只有一个?)。

标签: ruby-on-rails ruby activerecord


【解决方案1】:

您可以使用一些选项。

您可以在 ContactInformation 模型上使用 validates_uniqueness_of

class ContactInformation < ActiveRecord::Base
  validates_uniqueness_of :user_id
end

但是,这将查询数据库以确保每次保存时不存在重复,并且可能会非常慢。

另一种选择是让您的数据库为您处理这个问题。根据您使用 ActiveRecord 的内容,在 contact_informations 表的 user_id 列上添加唯一性约束可能很有价值。

如果你的数据集很大,我建议不要使用validates_uniqueness_of,否则它可能是完美的。

确保至少为该表的user_id 列添加索引:

class AddIndexOnContactInformationToUserId < ActiveRecord::Migration
  add_index :contact_information, :user_id
end

【讨论】:

    【解决方案2】:

    您需要进行验证,但不需要自定义验证:

    class ContactInformation < ActiveRecord::Base
      belongs_to :user
      validates_uniqueness_of :user_id
    end
    

    您可能还想在数据库中为该列添加唯一索引。它不仅可以提高查询的性能,还可以保护您的应用免受race conditions in case you are running multiple instances of it in parallel 的侵害。

    【讨论】:

    • validates_uniqueness_of 似乎运行良好,感谢 Jesuspc!
    猜你喜欢
    • 2015-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多