我有两个像这样的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
我想知道是否有更多的方法可以解决这个问题?或者我是否需要为所有has_one关系创建这样的自定义验证器?
由于
答案 0 :(得分:1)
您需要进行验证,但不需要自定义验证:
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。
答案 1 :(得分:1)
您可以选择几种方式。
您可以在ContactInformation
型号上使用validates_uniqueness_of:
class ContactInformation < ActiveRecord::Base
validates_uniqueness_of :user_id
end
然而,这将查询数据库以确保每次保存都不存在重复项,并且可能非常慢。
另一个选择是让您的数据库为您处理此问题。根据您使用ActiveRecord
的内容,在user_id
表的contact_informations
列上添加唯一性约束可能很有价值。
如果你的数据集很大,我建议不要使用validates_uniqueness_of
,否则它可能是完美的。
确保至少在该表的user_id
列中添加索引:
class AddIndexOnContactInformationToUserId < ActiveRecord::Migration
add_index :contact_information, :user_id
end