2012-01-30 5 views
7

Tengo dos modelos: el descuento tiene y pertenece a muchos Businsses.Cómo puedo agregar un error de validación en callbacks de asociación before_save

Quiero validar que un descuento siempre tenga al menos un negocio, junto con otra condición (por ejemplo active?). He intentado lo siguiente:

class Discount < ActiveRecord::Base 
    has_and_belongs_to_many :businesses, 
    before_remove: :validate_publish_status 

    def validate_publish_status(*arg) 
    if active? && businesses.count == 0 
     errors[:active] << 'discount with no business' 
    end 
    end 
end 

Sin embargo, esto no funciona (no hay errores de validación criados) y me di cuenta de que esto es probablemente porque es sólo una devolución de llamada, no una validación. ¿Cómo puedo codificarlo para poder usar el errors como lo hago con la validación personalizada?

La acción del controlador que tengo (Ajax):

def remove 
    @business = Business.find(params[:business_id]) 
    if @business.in? @discount.businesses 
     @discount.businesses.delete(@business) 
    end 
    render json: @business.as_json(only: [:id, :type, :name, :address], 
            methods: [:city_name, :country_name]). 
     merge(paths: paths_for(@discount, @business)) 
    rescue ActiveRecord::RecordInvalid # even tried the generic Exception 
    respond_to do |f| 
     f.json { render json: {error: $!.message}, status: 403 } 
    end 
    end 

Respuesta

8

Podría ser su sintaxis en la devolución de llamada before_remove o lo que está sucediendo en el método de validación en sí. También es posible que desee agregar algún código de depuración en el método de devolución de llamada para ver si incluso está haciendo allí.

* Tenga en cuenta que la transacción solo se detendrá si se produce una excepción en el método de devolución de llamada. Dado que este es el caso, es probable que desee para manejar la lógica excepción en su controlador que volver a hacer la acción:

class Discount < ActiveRecord::Base 
    has_and_belongs_to_many :businesses, :before_remove => :validate_publish_status 

    def validate_publish_status(*args) 
    if yyy? && businesses.count == 0 
    errors.add(:yyy,'discount with no business') 
    raise "Unable to remove business." 
    end 
    end 

end 

controlador de GIST:

def update 
    @company.find(params[:id]) 
    if @company.update_attributes(params[:company]) 
     ... 
    else 
     render :action => 'edit' 
    end 
    rescue 
    render :action=>'edit' 
    end 

Nota del Association Callback Documentation.

+0

gracias, lo revisé y se ejecutó a través del método. Si 'raise' error'' aumentaría el error como se esperaba. – lulalala

+0

Actualicé la respuesta con algo más de información. Deberá plantear una excepción en la devolución de llamada para detener la transacción. Al hacerlo, es probable que desee hacer algún manejo de excepciones en el controlador para volver a procesar la acción. – miked

+2

También puede devolver falso para detener la ejecución. "Toda la cadena de devolución de llamada está envuelta en una transacción. Si cualquier método de devolución de llamada anterior devuelve exactamente falso o genera una excepción, la cadena de ejecución se detiene y se emite un ROLLBACK; después de las devoluciones de llamada solo puede lograr eso al generar una excepción". http://guides.rubyonrails.org/active_record_validations_callbacks.html#halting-execution – amree

2

Usted puede utilizar el método validates con :presence => true para esto.

class Discount < ActiveRecord::Base 
    has_and_belongs_to_many :businesses 
    validates :businesses, :presence => true 
end 

Usando :presence => true en un validador de asociación se asegurará de que existe al menos un miembro de la asociación.

+0

gracias pero necesito verificar un campo adicional en esa validación (la parte yyy?). Entonces debo escribir una validación personalizada. – lulalala

+1

¿Puedes editar tu pregunta y ofrecer una mejor descripción de lo que estás buscando exactamente? No dices nada acerca de yyy ni de lo que se supone que debe ser en tu descripción, y en realidad no está claro en tu código lo que estás tratando de hacer con yyy. –

+0

mi mal, he reformulado yyy? a activo? Pero puede ser cualquier expresión arbitraria que evalúe a boolean. – lulalala

Cuestiones relacionadas