validar rails formularios campos asociaciones anidados ruby-on-rails validation callback single-table-inheritance

ruby-on-rails - formularios - rails asociaciones



¿Cómo puedo desactivar una validación y devoluciones de llamada en un modelo derivado de STI de rieles? (7)

Al hurgar en la fuente (actualmente estoy en Rails 1.2.6), las devoluciones de llamada son relativamente sencillas.

Resulta que los before_validation_on_create , before_save etc., si no se invocan con ningún argumento, devolverán la matriz que contiene todas las devoluciones de llamada actuales asignadas a ese ''sitio de devolución de llamada''

Para borrar los before_save, simplemente puede hacer

before_save.clear

Y parece funcionar

Dado un modelo

class BaseModel < ActiveRecord::Base validates_presence_of :parent_id before_save :frobnicate_widgets end

y un modelo derivado (la tabla de base de datos subyacente tiene un campo type - esto es STI de rails simples)

class DerivedModel < BaseModel end

DerivedModel heredará todos los comportamientos de BaseModel , incluida la validates_presence_of :parent_id . Me gustaría desactivar la validación de DerivedModel y evitar que los métodos de devolución de llamada se DerivedModel , preferiblemente sin modificar o romper el BaseModel

¿Cuál es la forma más fácil y más robusta de hacer esto?


Al volver a hurgar en la fuente, parece que las validaciones se pueden ejecutar en cada operación de guardado o solo en las actualizaciones / creaciones. Esto se asigna a

:validate => all guarda
:validate_on_create => creaciones solamente
:validate_on_update => updates only

Para borrarlos, puedes usar write_inheritable_attribute , así:

write_inheritable_attribute :validate, nil


Me gusta usar el siguiente patrón:

class Parent < ActiveRecord::Base validate_uniqueness_of :column_name, :if => :validate_uniqueness_of_column_name? def validate_uniqueness_of_column_name? true end end class Child < Parent def validate_uniqueness_of_column_name? false end end

Sería bueno si Rails proporcionara un método skip_validation para evitar esto, pero este patrón funciona y maneja bien las interacciones complejas.


Como una variación de la respuesta de @Jacob Rothstein, puedes crear un método en el padre:

class Parent < ActiveRecord::Base validate_uniqueness_of :column_name, :unless => :child? def child? is_a? Child end end class Child < Parent end

El beneficio de este enfoque es que no necesita crear múltiples métodos para cada nombre de columna para el que necesita desactivar la validación en la clase Child.


Aquí hay una pequeña variación de RubyDev que he estado usando en mongoid 3 .

class Parent include Mongoid::Document validates :column_name , uniqueness: true, unless: Proc.new {|r| r._type == "Child"} end class Child < Parent end

Hasta ahora ha estado funcionando bastante bien para mí.


Una forma más limpia es esta:

class Parent < ActiveRecord::Base validate :column_name, uniqueness: true, if: ''self.class == Parent'' end class Child < Parent end

O puede usarlo también de esta manera:

class Parent < ActiveRecord::Base validate :column_name, uniqueness: true, if: :check_base private def check_base self.class == Parent end end class Child < Parent end

Entonces, la validación de unicidad se hace si la clase de instancia del modelo es Parent .

  1. La clase de instancia de Child is Child y difiere de Parent .
  2. La clase de instancia de Parent es Parent y es igual a Parent .

Desde rails 3.0 también puede acceder al método de la clase de validators para manipular y obtener una lista de todas las validaciones. Sin embargo, no puede manipular el conjunto de validaciones a través de esta matriz.

Al menos a partir de Rails 5.0, sin embargo, parece ser capaz de manipular el _validators (no documentado).

Usando este método puedes modificar las validaciones en la subclase como por ejemplo:

class Child < Parent # add additional conditions if necessary _validators.reject! { |attribute, _| attribute == :parent_id } end

Si bien esto utiliza un método no documentado, tiene el beneficio de no requerir que la superclase sepa nada sobre la implementación del niño.