ruby on rails - How to validate that payment can never cause invoice amount payable to be less than zero? -


i have class:

class payment < activerecord::base    attr_accessible :amount, :invoice_id    belongs_to :invoice    validates :amount, :numericality => { :greater_than => 0, :less_than_or_equal_to => :maximum_amount }    after_save    :update_amount_payable   after_destroy :update_amount_payable    private    def maximum_amount     invoice.amount_payable   end    def update_amount_payable     invoice.update_amount_payable   end  end 

class invoice < activerecord::base    has_many :payments    after_save :update_amount_payable    def update_amount_payable     update_column(:amount_payable_in_cents, new_amount_payable)   end    private    def new_amount_payable     (total - payments.map(&:amount).sum) * 100   end  end 

the code above works. how can validate no payment amount can ever cause invoice.amount_payable less 0?

especially when multiple payments same invoice possible, turns out tricky.

i've been trying head around hours, no avail. maybe after callback rollback database can used here?

thanks help.

one cross-database solution work use optimistic locking. essentially, requires special lock_version column, checked whenever update made. if lock_version @ time update called different model expecting, throws error noting outside of model caused record change (thus invalidating update). activerecord supports out of box, , suffice needs if don't mind blocking concurrent transactions altogether.

a case won't work want allow concurrent updates. in case, you'll need manually check result during update:

def update_amount_payable   new_value = new_amount_payable   raise "payment amounts can't greater total invoice amount" if new_value < 0   count = invoice.where(id: id, amount_payable_in_cents: amount_payable_in_cents).                   update_all(amount_payable_in_cents: new_value)   raise activerecord::staleobjecterror.new(self, 'update amount_payable_in_cents') if count != 1 end  private  def new_amount_payable   (total - payments.sum(:amount)) * 100  # amount sum database end 

Comments

Popular posts from this blog

c# - DetailsView in ASP.Net - How to add another column on the side/add a control in each row? -

javascript - firefox memory leak -

Trying to import CSV file to a SQL Server database using asp.net and c# - can't find what I'm missing -