2009-05-27 19 views
7

Estoy trabajando en una aplicación Rails que los usuarios existentes pueden invitar a miembros adicionales a unirse. El problema con esto es que el modelo de Usuario existe en diferentes estados y en esos diferentes estados, se requieren diferentes conjuntos de información.Validación multi estado en Rails

Por ejemplo, John es miembro del sitio e invita a Mary. John ingresa el nombre y la dirección de correo electrónico de Mary, se crea un registro de usuario en la base de datos de Mary y se envía un correo electrónico de invitación. Sin embargo, después de que ella se una, el conjunto requerido de datos cambia y le solicitamos que ingrese información adicional (por ejemplo, una contraseña).

Todavía estoy aprendiendo Ruby on Rails y no veo ninguna manera de manejar esto utilizando las técnicas de validación estándar de validates_presence_of, validates_format_of, etc. Puede alguien me punto en la dirección correcta

Respuesta

9

Lo más fácil es :if utilizar de la siguiente manera:

class User < ActiveRecord::Base 
    validate_presence_of :name 
    validate_presence_of :age, :if => Proc.new { |user| user.signup_step >= 2 } 
    # ... etc 
end 

o:

class User < ActiveRecord::Base 
    validate_presence_of :name 
    validate_presence_of :age, :if => :registering? 

    def registering? 
    signup_step >= 2 
    end 
end 

también puede utilizar la meto validate d para definir cualquier lógica compleja y personalizada. Por ejemplo:

class User < ActiveRecord::Base 
    validate :has_name_and_email_after_invitation 
    validate :has_complete_profile_after_registration 

    def has_name_and_email_after_invitation 
    if ... # determine if we're creating an invitation 
     # step 1 validation logic here 
    end 
    end 

    def has_complete_profile_after_registration 
    if ... # determine if we're registering a new user 
     # step 2 validation logic here 
    end 
    end 
end 

(En el ejemplo anterior, en realidad se podría definir las reglas de validación en has_name_and_email_after_invitation con validates_xxx_of llamadas regulares, debido a que deben aplicarse en el paso 2, así, pero utilizando dos métodos de las etapas separadas le da máxima flexibilidad)

+1

Gracias, que era una excelente explicación. – Jason

+1

Sigue siendo una muy buena respuesta, es difícil encontrar algo sobre este asunto en particular. Estaba construyendo un carrito de compras y esta respuesta es muy útil. –

5

Y, por DRYin'up su código un poco, se puede utilizar with_options, así:.

class Example < ActiveRecord::Base 
    [...] 
    def registering? 
    signup_step >= 2 
    end 
    with_options(:if => :registering?) do |c| 
    c.validates_presence_of :name 
    end 

    with_options(:unless => :registering?) do |c| 
    c.validates_presence_of :contact_details 
    end 
    [...] 
end 

saber más acerca de with_options aquí:

http://apidock.com/rails/v2.3.2/Object/with_options

Incluso hay un screencast por Railscasts:

http://railscasts.com/episodes/42-with-options

Cuestiones relacionadas