Over on rails-core, I posted Edge Rails fails saving parent when has_many child ?.

The models I am using are:

1
2
3
4
5
class Invoice < ActiveRecord::Base
  belongs_to :customer
  has_many :lines, :class_name => 'InvoiceItem'
  validates_presence_of :no, :customer
end
1
2
3
4
class InvoiceItem < ActiveRecord::Base
  belongs_to :invoice
  validates_presence_of :invoice
end

As is, it was impossible to use the normal build and save idiom:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ruby script\console
Loading development environment.
>> invoice = Invoice.new
=> #<Invoice:0x3a76060 ...>
>> line = invoice.lines.build
=> #<InvoiceItem:0x3a5d610 ...>
>> invoice.save!
ActiveRecord::RecordInvalid: Validation failed: Lines is invalid
        from 
./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:736:in
`save!'
        from (irb):3
>> puts line.errors.full_messages
Invoice can't be blank

Well, of course. I know invoice can’t be blank. If I remove :invoice from the validates_presence_of, things work out fine:

1
2
3
4
5
6
7
8
9
10
...
>> invoice.save!
=> nil
>> invoice.new_record?
=> false
>> line.new_record?
=> false
>> line.invoice
=> nil
>> # Huh?

Digging into the code, ActiveRecord::Associations::AssociationProxy#set_belongs_to_association_for it turns out that only the foreign key is assigned to the child instance, not the full parent model. The behavior as seen above is therefore “normal”.

Turns out that if I validate the foreign key instead, things work perfectly:

1
2
3
4
class InvoiceItem < ActiveRecord::Base
  belongs_to :invoice
  validates_presence_of :invoice_id
end
1
2
3
4
5
6
7
...
>> invoice.save!
=> nil
>> line.new_record?
=> false
>> line.invoice
=> #<Invoice:0x39fbea8 ...>

Lesson learned: don’t validate the presence of the associated model, only it’s foreign key.

 

Search

A picture of me

I am François Beausoleil, a Ruby on Rails coder. During the day, I work on XLsuite. At night, I am interested many things. Read my biography

Tags

(3) (1) (0) (2) (1) (1) (2) (2) (1) (2) (1) (2) (1) (2) (1) (1) (1) (1) (2) (14) (1) (1) (1) (1) (2) (1) (1) (2) (0) (1) (2) (1) (3) (1) (1) (1) (1) (1) (1) (0) (3) (2) (1) (2) (2) (1) (3) (2) (8) (8) (9) (12) (1) (1) (3) (1) (1) (1) (1) (1) (1) (2) (2) (2) (1) (1) (3) (1) (3) (1) (0) (23) (1) (1) (0) (1) (1) (1) (23) (25) (1) (1) (13) (1) (1) (2) (3) (1) (1) (4) (1) (2) (3) (0) (1) (7) (3) (1) (5) (5) (2) (2) (2) (4) (6) (7) (1) (0) (1) (1) (2) (2) (1) (4) (12) (2) (1) (2) (4) (1) (1) (1) (2) (8) (2) (3) (2) (2) (1) (3) (1) (1)

Links

Projects I work on

Categories

Archives