Rails仅在有条件时才validation唯一性

我有一个问题类:

class Question  :user_id end 

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

我遇到的麻烦是我只想要非管理员用户的约束。 因此,管理员可以根据需要每天创建尽可能多的问题。 关于如何优雅地实现这一点的任何想法?

您可以通过将要执行的简单Ruby字符串,Proc或方法名称作为符号作为值传递给:if:unless在validation选项中, :unless可以进行validation条件。 这里有些例子:

在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指南中的条件validation部分: http : //edgeguides.rubyonrails.org/active_record_validations.html#conditional-validation

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

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

只需在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 

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

 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