ruby on rails - validates_uniqueness_of - Los rieles validan la singularidad solo si son condicionales
rails validations (3)
Tengo una clase de preguntas:
class Question < ActiveRecord::Base
attr_accessible :user_id, :created_on
validates_uniqueness_of :created_on, :scope => :user_id
end
Un usuario determinado solo puede crear una única pregunta por día, por lo que quiero forzar la unicidad en la base de datos a través de un índice único y la clase de Pregunta a través de validates_uniqueness_of.
El problema con el que me estoy topando es que solo quiero esa restricción para usuarios que no son administradores. Así que los administradores pueden crear tantas preguntas por día como quieran. ¿Alguna idea de cómo lograrlo con elegancia?
La única forma que conozco para garantizar la singularidad es a través de la base de datos (por ejemplo, un índice único). Todos los enfoques basados en Rails solo involucran condiciones de carrera Dadas sus limitaciones, creo que lo más fácil sería establecer una columna separada e indexada de forma única que contenga una combinación del día y la identificación del usuario, que dejaría null
para los administradores.
En cuanto a validates_uniqueness_of
, puede restringir la validación a no administradores mediante el uso de una opción if
o unless
, como se explica en http://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of
Puede hacer que una validación sea condicional pasando una cadena simple de Ruby para ser ejecutada, un Proc o un nombre de método como un símbolo como un valor a :if
o :unless
en las opciones para su validación. Aquí hay unos ejemplos:
Antes de la versión 5.2 de Rails, podría pasar una cadena:
# using a string:
validates :name, uniqueness: true, if: ''name.present?''
Desde 5.2 en adelante, las cadenas ya no son compatibles, dejándole las siguientes opciones:
# 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
En tu caso, podrías hacer algo como esto:
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
Eche un vistazo a la sección de validación condicional en las guías de rieles para obtener más detalles: http://edgeguides.rubyonrails.org/active_record_validations.html#conditional-validation
Solo agregue una condición a la llamada 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
Pero aún mejor, solo crea una validación personalizada:
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