我有2个表:用户和成员(这些表示两种类型的用户)。两个表都包含两列:email
和new_email
。我希望在模型和迁移文件中进行验证,以便电子邮件地址只能在这四列中存在一次(因此每列中不会出现一次,但所有四列一起使用)。怎么实现这个?到目前为止,我有:
1.Member Model(也包括用户模型文件):
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true,
length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { scope: :new_email, case_sensitive: false }
validate :uniqueness_of_email_across_models
validates :new_email, presence: true,
length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { scope: :email, case_sensitive: false }
validate :uniqueness_of_new_email_across_models
private
def uniqueness_of_email_across_models
if User.where("lower(email) in (?)", [self.email.downcase, self.new_email.downcase]).first
errors.add(:email, "There is already a user with this email address")
end
end
def uniqueness_of_new_email_across_models
if User.where("lower(new_email) in (?)", [self.email.downcase, self.new_email.downcase]).first
errors.add(:new_email, "There is already a user with this email address")
end
end
我认为scope: :new_email
是一个不正确的实现。我认为这会测试两列之间组合的唯一性,而不是两列中值的唯一性组合?
也许客户验证器是合适的吗?也就是说,将私有方法添加到行中(检查成员表,与在用户表中检查的方式相同):
if self.where("lower(email) in (?)", [self.email.downcase, self.new_email.downcase]).first
errors.add(:email, "There is already a user with this email address")
2.会员迁移:
t.string :new_email
t.datetime :activation_sent_at
add_index :members, [:email, :new_email], unique: true
不确定迁移文件中如何在一列(i.q.)之外包含所有四列的唯一性。目前的实现,我认为只检查电子邮件和new_email的组合,而不是查看另一个表。
更新:我想更大的问题是如何实现我想要实现的目标。我现在认为不能验证new_email
的唯一性可能更容易。相反,当用户点击确认链接并且应用想要使用email
覆盖new_email
时,此时会应用唯一性验证。这会是一个更合适的实施吗?