添加唯一性:值只能在2个表中的四列上发生一次

时间:2015-06-01 14:51:39

标签: ruby-on-rails ruby postgresql validation ruby-on-rails-4

我有2个表:用户和成员(这些表示两种类型的用户)。两个表都包含两列:emailnew_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时,此时会应用唯一性验证。这会是一个更合适的实施吗?

0 个答案:

没有答案