Topic: Validating against values in other records

I'm working on an auction service atm. Here's what I'm trying to accomplish:

- A bid must be higher than any previous bids on the same item.
- A bid must be higher than the min bid value set by the seller.

This pseudo-code is the best I came up with, but it's not working:

class Bid < ActiveRecord::Base
  validates_exclusion_of :amount, :in => 0..Bid.find_all_by_item_id(bid.item_id).max
  validates_exclusion_of :amount, :in => 0..Item.find(bid.item_id).min_bid
  validates_numericality_of :amount
end

The main problem is I don't know how to refer to the bid-data (bid.item_id) from within the model.

If at all possible I'd like to do this validation in the model, but I'm suspecting I might need to move it to the controller?

Re: Validating against values in other records

I dont know how to do refer the bid date ether, however you can put a method in the model so its still in the model and its still a validation.

protected
      def validate
        errors.add...
      end

more info here

--

Re: Validating against values in other records

You can always write your own custom validation code in the model using validates_each.  Why not do something like this?

class Bid < ActiveRecord::Base
  validates_each :amount do |model, attr, value|
    if value < model.item.min_bid
      model.errors.add(attr, "Your bid is below the minimum for this item.")
    elsif value < model.item.bids.max
      model.errors.add(attr, "There is already a bid higher than yours.")
    end
  end
end

You have to have your associations set up properly for that code to work, but it should perform the validations that you're looking for.

Re: Validating against values in other records

Thanks for the inspiration guys. I finally went with:

   def validate
      errors.add_to_base("There is already a bid higher than yours.") unless highest_bid?(amount, item_id)
      errors.add_to_base("Your bid is below the minimum for this item.") unless over_min?(amount, item_id)
   end

  def highest_bid?(bid, item)
    all_bids = Array.new
    Bid.find_all_by_item_id(item).each {|am| all_bids << am.amount }
    bid >= all_bids.max + Item.find(item).inc ? true : false rescue true
  end

  def over_min?(bid, item)
    bid >= Item.find(item).min_bid rescue false
  end