views:

24

answers:

1

Say I open a Rails (2.3.8) script console and try this:

a = Account.new(:first_name) = 'foo'
i = a.invoices.build
p i.account.first_name

Account.rb is a model object and contains: has_many :invoices

and Invoice.rb is a model as well containing: belongs_to :account, :validate => true

In console line 3 above, i.account is nil. I realize that i.account would not be nil if account had been saved, but I do not wish to save an account unless I can create a valid invoice for the account. And, just for kicks, the invoice validation depends on some properties of the unsaved account.

Any ideas how to make this work?

Best, Will

A: 

I typically do this with transactions. With rails transactions you can perform db interactions and roll them back at any time if something fails to validate. For example: in your model:

def save_and_create_invoice
  Account.transaction do
     #first let's save the account, this will give us an account_id to work with
     return false unless self.save
     invoice = self.invoices.build
     #setup your invoice here and then save it
     if invoice.save
         #nothing wrong? return true so we know it was ok
         return true
     else
         #add the errors so we know what happened
         invoice.errors.full_messages.each{|err| errors.add_to_base(err)}
         #rollback the db transaction so the account isn't saved
         raise ActiveRecord::Rollback
         #return false so we know it failed
         return false
     end
  end
end

And in your controller you would call it like so:

def create
 @account = Account.new(params[:account])
 respond_to do |format|
  if @account.save_and_create_invoice
     format.html
  else
     format.html {render :action => "new"}
  end
 end
end

Note that I didn't run this code to test it, just whipped it out real quick to show an example.

Ryan