views:

60

answers:

2

I've got the following models:

  • An Invoice has several statuses: Initially it's "draft", then it can be "sent", and "payed"
  • An Invoice has_many InvoiceLines. InvoiceLines have a text and a cost.

My question is: How can I perform the following validations?

If the Invoice Status is not draft:

  • No InvoiceLines can be added to it
  • The values of the invoiceLines can't be modified

Right now I've got this, but it's not working:

class Invoice < ActiveRecord::Base
  has_many :invoice_lines
  validates_associated :invoice_lines
end

class InvoiceLine < ActiveRecord::Base
  belongs_to :invoice
  validate :check_invoice_status

  def check_invoice_status
    unless self.invoice.draft?
      errors.add_to_base "Can't add or modify: the invoice status is not draft"
    end
  end
end

This does not work as intented since the validates_associated "allways fails"; once the invoice status is changed to "sent", the invoice lines are allways invalid. I only want them to be checked if "updated" or "added new".

Thaks.

+1  A: 

use "changed?" for invoice line:

def validate_invoice_status
  if changed? and !invoice.draft?
    errors.add_to_base "Can't add or modify: the invoice status is not draft"
  end
end
aivarsak
I didn't know about changed? - thanks for sharing this!
egarcia
A: 

try this:

    def check_invoice_status
        unless self.invoice.draft?
          self.reload if changed? && !new_record?
          errors.add_to_base("Can't add: the invoice status is not draft") if new_record?
        end
      end
thaold
This will still "allways add an error" - I believe the changed? bit has to be part of the condition, too: if changed? and !self.invoice.draft?makes more sense here.Also, I like the idea of reloading, but I don't think it will be necesary in this case - since the validations will prevent any update. Thanks for commenting anyway.
egarcia
I have never encountered this problem, but i logically:we can have 2 situation:1. when creating invoice_line 'new_record?'==true, 'changed?'==truecheck_invoice_status should add an error, because we haven't record in database and we haven't permissions to create it2. when updating current invoice_line, new_record? == false, but changed? == true, on this case we should reload invalid record, that we have now, from database, our record become valid, and validates_associated should pass it.Anyway, good that you found a way how to catch this.
thaold