Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add a validation error in before_save association callbacks

I have two models: The Discount has and belongs to many Businsses.

I want to validate that a Discount always have at least one business, together with another condition (for example active?). I tried the following:

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

However this does not work (no validation errors raised) and I realized that this is probably because it is only a callback, not a validation. How can I code it so I can use the errors like I do I custom validation?

The controller action I have (for 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
like image 998
lulalala Avatar asked Jan 30 '12 09:01

lulalala


2 Answers

Could be your syntax on the before_remove callback or what's happening in the validation method itself. You also might want to add some debug code in the callback method to see if it's even making in there.

*Note that the transaction will only be stopped if an exception is raised in the callback method. Since this is the case, you'll probably want to handle the exception logic in your controller to re-render the action:

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

controller gist:

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

Note the Association Callback Documentation.

like image 156
miked Avatar answered Nov 14 '22 18:11

miked


You can use the validates method with :presence => true for this.

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

Using :presence => true on an association validator will ensure that at least one member of the association exists.

like image 31
Ben Lee Avatar answered Nov 14 '22 19:11

Ben Lee