Rails ActiveRecord: Validar el atributo único
-
24-10-2019 - |
Pregunta
¿Si hay una forma en que pueda validar un atributo único en los rieles?
Algo como:
ac_object.valid?(attribute_name)
Lo usaré para la validación de AJAX de campos de modelos particulares. Mover estas validaciones al JavaScript hace que el código sea realmente feo.
Solución
Puede implementar su propio método en su modelo. Algo como esto
def valid_attribute?(attribute_name)
self.valid?
self.errors[attribute_name].blank?
end
O agregarlo a ActiveRecord::Base
Otros consejos
A veces hay validaciones que son bastante caras (por ejemplo, validaciones que necesitan realizar consultas de bases de datos). En ese caso, debe evitar usar valid?
Porque simplemente hace mucho más de lo que necesitas.
Hay una solución alternativa. Puedes usar el validators_on
método de ActiveModel::Validations
.
Validators_on (*atributos) público
Enumere todos los validadores que se están utilizando para validar un atributo específico.
según el cual puede validar manualmente los atributos que desea
por ejemplo, solo queremos validar el title
de Post
:
class Post < ActiveRecord::Base
validates :body, caps_off: true
validates :body, no_swearing: true
validates :body, spell_check_ok: true
validates presence_of: :title
validates length_of: :title, minimum: 30
end
Dónde no_swearing
y spell_check_ok
son métodos complejos que son extremadamente caros.
Podemos hacer lo siguiente:
def validate_title(a_title)
Post.validators_on(:title).each do |validator|
validator.validate_each(self, :title, a_title)
end
end
que validará solo el atributo de título sin invocar otras validaciones.
p = Post.new
p.validate_title("")
p.errors.messages
#=> {:title => ["title can not be empty"]
Nota
No estoy completamente seguro de que se supone que debemos usar validators_on
Safamente, por lo que consideraría manejar una excepción de manera sensata en validates_title
.
Terminé construyendo la respuesta de @xlembouras y agregué este método a mi ApplicationRecord
:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
def valid_attributes?(*attributes)
attributes.each do |attribute|
self.class.validators_on(attribute).each do |validator|
validator.validate_each(self, attribute, send(attribute))
end
end
errors.none?
end
end
Entonces puedo hacer cosas como esta en un controlador:
if @post.valid_attributes?(:title, :date)
render :post_preview
else
render :new
end