Harakiri
Harakiri

Reputation: 730

Rails: validates_length_of

I want to validate the Discount of a Sale in my Sale model.

The form for creating a Sale receives the Product data from my Warehouse model and saves it inside the Sale record:

<%= f.select(:product, Warehouse.pluck(:product).uniq, {prompt:true}, {class: 'form-control'}) %>

The Warehouse model has the discount specified for this respective product. Now I want to check if the sale.product is equal to the warehouse.product and then set the discount limit for this sale. Is that possible? Something like this:

validates_length_of :discount, maximum: Warehouse.where(:product => @sales.product).pluck(:discount), message: "Discount is to high"

Many Thanks in advance!

Upvotes: 3

Views: 1421

Answers (4)

D-side
D-side

Reputation: 9485

First of all, you should be validating numericality for numeric values.

Custom validation is unnecessary. You don't have to use constants or literals or other class-evaluation time values! Use procs! They will be called!

You pass a key as a comparison and then a proc as a value, so it is called during validation.

valudates_numericality_of :discount,
  less_than_or_equal_to: proc { |model| Something.query(whatever).pluck(:wow) },
  message: "is too high"

Note: you should probably also add a check for whether it's positive.


Bonus (pure fun, best not use): almost the same code with a spectacular amount of arrows
(in order: symbol <=, hashrocket =>, stabby-lambda -> () {}):

valudates_numericality_of :discount,
  :<= => -> (model) { Something.query(whatever).pluck(:wow) },
  :message => "is too high"

Note that 1.9 hash syntax won't work with a symbol like <= (like <=: value) so you have to stick to a hashrocket with this one, which is... another bit of pure fun.

Upvotes: 5

Richard Peck
Richard Peck

Reputation: 76774

To add to D-side's answer (and to use this reference), you'll want to also work with the relevant data (not calling a new db query):

#app/models/sale.rb
class Sale < ActiveRecord::Base
    belongs_to :product, class_name: "Warehouse", foreign_key: "product", inverse_of: :sales
    validates :discount, numericality: { less_than_or_equal_to: Proc.new{|sale| sale.product.discount } } 

end

#app/models/warehouse.rb
class Warehouse < ActiveRecord::Base
     has_many :sales, inverse_of: :product
end

Upvotes: 0

Alexander Shlenchack
Alexander Shlenchack

Reputation: 3869

For this task you should use a custom validation. Please see: http://guides.rubyonrails.org/active_record_validations.html#custom-methods

Upvotes: 0

Rajarshi Das
Rajarshi Das

Reputation: 12320

You can try to use a custom validation

in your model

validate :maximum_discout

  def maximum_discount
    if Warehouse.where(:product => @sales.product).pluck(:discount).all?{|d| d > self.discount }
      errors.add(:discount, "It should not cross the maximum discount")
    end
  end

Upvotes: 0

Related Questions