【问题标题】:Rails validate uniqueness only if conditionalRails 仅在有条件的情况下验证唯一性
【发布时间】:2014-01-03 23:54:58
【问题描述】:

我有一个问题类:

class Question < ActiveRecord::Base
  attr_accessible :user_id, :created_on

  validates_uniqueness_of :created_on, :scope => :user_id
end

给定用户每天只能创建一个问题,因此我想通过唯一索引强制数据库中的唯一性,并通过 validates_uniqueness_of 强制问题类。

我遇到的问题是我只希望非管理员用户使用该约束。因此,管理员每天可以根据需要创建任意数量的问题。关于如何优雅地实现这一目标的任何想法?

【问题讨论】:

    标签: ruby-on-rails validates-uniqueness-of


    【解决方案1】:

    您可以通过将要执行的简单 Ruby 字符串、Proc 或方法名称作为值作为值传递给验证选项中的 :if:unless 来使验证成为条件。以下是一些示例:

    在 Rails 5.2 版本之前,您可以传递一个字符串:

    # using a string:
    validates :name, uniqueness: true, if: 'name.present?'
    

    从 5.2 开始,不再支持字符串,为您提供以下选项:

    # using a Proc:
    validates :email, presence: true, if: Proc.new { |user| user.approved? }
    
    # using a Lambda (a type of proc ... and a good replacement for deprecated strings):
    validates :email, presence: true, if: -> { name.present? }
    
    # using a symbol to call a method:
    validates :address, presence: true, if: :some_complex_condition
    
    def some_complex_condition
      true # do your checking and return true or false
    end
    

    在你的情况下,你可以这样做:

    class Question < ActiveRecord::Base
      attr_accessible :user_id, :created_on
    
      validates_uniqueness_of :created_on, :scope => :user_id, unless: Proc.new { |question| question.user.is_admin? }
    end
    

    有关详细信息,请查看 rails 指南上的条件验证部分:http://edgeguides.rubyonrails.org/active_record_validations.html#conditional-validation

    【讨论】:

    • 不再支持将字符串传递给if 条件。
    • 感谢您的提醒 - 将使用详细信息更新答案。
    • 也可以是validates :email, uniqueness: true, if: :name?
    • 我的回答中已经提到了使用符号调用方法。
    【解决方案2】:

    我知道保证唯一性的唯一方法是通过数据库(例如唯一索引)。所有基于 Rails 的方法都涉及竞争条件。鉴于您的限制,我认为最简单的方法是建立一个单独的、唯一索引的列,其中包含日期和用户 ID 的组合,您可以将 null 留给管理员。

    对于validates_uniqueness_of,您可以通过使用ifunless 选项将验证限制为非管理员,如http://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of 中所述

    【讨论】:

      【解决方案3】:

      只需在validates_uniqueness_of 调用中添加一个条件。

      validates_uniqueness_of :created_on, scope: :user_id, unless: :has_posted?
      def has_posted
        exists.where(user_id: user_id).where("created_at >= ?", Time.zone.now.beginning_of_day)
      end
      

      但更好的是,只需创建一个自定义验证:

      validate :has_not_posted
      def has_not_posted
        posted = exists.where(user: user).where("DATE(created_at) = DATE(?)", Time.now)
        errors.add(:base, "Error message") if posted
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多