【问题标题】:Unique Validation on one column and conditional on second column based on row value基于行值的一列的唯一验证和第二列的条件
【发布时间】:2021-02-20 06:03:54
【问题描述】:

我有一个数据库,其中电子邮件被设置为具有状态的唯一验证。我已将范围设置为 int 'status',当特定帐户处于活动状态时为 1。 因此,如果用户切换他的国家,他的帐户状态将切换为 0,并使用相同的电子邮件创建一个新帐户,并将状态设置为 1。 所以为了解决这个问题,我在“电子邮件”和“状态”上使用了一个复合唯一键,

validates :email, uniqueness: { scope: :status }

所以,让我们进行一次小试运行。 目前,用户在 X 国家,他的电子邮件是 abc@xyz.com 所以数据库可能看起来像

email: abc@xyz.com
status: 1

现在如果他去 Y 国 数据库更新为,

[for company X]
email: abc@xyz.com
status: 0
[for company Y]
email:abc@xyz.com
status: 1

工作正常 但是现在如果我们的旅行者现在去 Z 国 数据库将像现在一样卡住,因为公司 Y 状态将更新为 0,并且现在这种组合不是唯一的,因此将返回错误。 这里也是一项具有挑战性的任务,仅使用电子邮件和状态作为键。 我想要实现的是,对于特定的电子邮件 status:1 必须是唯一的,而 status:0 可以是任意次数。 所以我试图将语句设置为

validates :email, uniqueness: { scope: :status }, if: :status == 1

但没有运气,因为我无法在模型中获取特定用户的状态值。 提前致谢!! PS:我是ROR的新手,所以请提供相关链接,以便我了解更多xD。

【问题讨论】:

    标签: ruby-on-rails postgresql ruby-on-rails-5


    【解决方案1】:

    您可能需要重新考虑您的数据库结构。

    但其中一种解决方案是:

    validates_uniqueness_of :email, scope: :status, if: :active?
    
    def active?
      status == 1
    end
    

    检查此验证的 api here

    但我强烈建议您重做数据库结构,以防止在数据库级别发生这种情况。比如:

    inactive_emails table
    email              |    company
    --------------------------------
    one@exmaple.com    |     A
    one@example.com    |     B
    one@example.com    |     C
    two@example.com    |     A
    
    
    active_emails table
    email              |    company
    --------------------------------
    one@example.com    |      D
    two@example.com    |      E
    

    对于非活动电子邮件模型,您可以:

    class InactiveEmails
      validates_uniqueness_of :email, scope: :company
    end
    

    对于活动电子邮件模型:

    class ActiveEmails
      validates_uniqueness_of :emails, scope: :company
    end
    

    这样,您可以确保每家公司都有唯一的有效电子邮件,并且每封电子邮件一次只能对一家公司有效。

    现在由您在两个表格之间切换电子邮件。例如,您可以使用回调:

    before_save :check_if_email_is_inactive_for_company
    
    def check_if_email_is_inactive_for_company
      if InactiveEmail.where(email: email, company: company).exists?
        # remove from inactive? or inform user this email was deactivated before?
      end
    end
    

    Rails API page 是你的朋友。

    【讨论】:

      【解决方案2】:

      您可以通过多种方式解决您的问题,但我会告诉您两种方式

      1. 您可以按如下方式应用范围

        validates :email, uniqueness: { scope: [:status,:country]}  
        
      2. 如果你想在单个字段上处理它

        validates :email, uniqueness: { scope: :status }, unless: lambda{ |user| user.status == 0 }
        

      如果user id是x,上面的验证允许user id: x, status: 0多次,但是你只能有一个user_id: x, status 1的组合。

      【讨论】:

        猜你喜欢
        • 2015-07-09
        • 1970-01-01
        • 2014-05-24
        • 2020-04-13
        • 1970-01-01
        • 2021-07-17
        • 2022-11-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多