2014-01-03 4 views
23

У меня есть класс Вопрос:Rails проверки уникальности, только если условное

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

    validates_uniqueness_of :created_on, :scope => :user_id 
end 

Данный пользователь может создать только один вопрос в день, поэтому я хочу, чтобы заставить уникальность в базе данных с помощью уникального индекса и вопрос класса через validates_uniqueness_of.

Проблема, с которой я сталкиваюсь, заключается в том, что я хочу только этого ограничения для пользователей, не являющихся администраторами. Поэтому администраторы могут создавать столько вопросов в день, сколько захотят. Любые идеи о том, как добиться этого элегантно?

ответ

59

Вы можете сделать проверку условную, передавая либо простую строку Ruby, должна быть выполнена , Proc или имя метода в качестве символа в качестве значения либо :if, либо :unless в параметрах для вашей проверки. Вот некоторые примеры:

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

# using a Proc: 
validates :email, presence: true, if: Proc.new { |user| user.approved? } 

# using 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 

Посмотрите раздел условной проверки на рельсы направляющих для более подробной информации: http://edgeguides.rubyonrails.org/active_record_validations.html#conditional-validation

+0

Полезной благодарность за Джон. – Abram

4

Единственный способ, которым я знаю, чтобы гарантировать уникальность, - это база данных (например, уникальный индекс). Все подходы, основанные только на Rails, включают условия гонки. Учитывая ваши ограничения, я бы подумал, что проще всего создать отдельный, однозначно проиндексированный столбец, содержащий комбинацию дня и идентификатора пользователя, который вы оставите null для администраторов.

Что касается validates_uniqueness_of, вы можете ограничить проверку на не-админов за счет использования опции if или unless, как описано в http://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of

0

Просто добавьте условие к вызову 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 
Смежные вопросы