This project is archived and is in readonly mode.
has_many .build does not set reverse reflection
Reported by Bryan Larsen | November 24th, 2009 @ 09:29 PM
class Category < ActiveRecord::Base
has_many :things, :dependent => :destroy
end
class Thing < ActiveRecord::Base
belongs_to :category
validates_presence_of :category
end
>> c=Category.new
>> t=c.things.build
>> c.save
=> false
>> pp c.errors
#<ActiveRecord::Errors:0x7f24100e2528
@base=#<Category id: nil, created_at: nil, updated_at: nil, name: nil>,
@errors=
{"things"=>
[#<ActiveRecord::Error:0x7f24100cdbc8
@attribute=:things,
@base=#<Category id: nil, created_at: nil, updated_at: nil, name: nil>,
@message=:invalid,
@options={},
@type=:invalid>]}>
=> nil
This seems very wrong to me. Things has a category, it was created through a category!
I certainly expect t.category_id
to return nil.
However, I would expect t.category
to return the
category. To work around the problem you have to insert a
>> t.category = c
before the save. Which is probably fine for most people. But in my code, that ends up being:
>> record.send("#{owner.class.reverse_reflection(association_name).name}=", owner)
So I went "UGH!" and opened this bug.
Comments and changes to this ticket
-
Mike Gehard July 27th, 2010 @ 01:59 AM
- Importance changed from to
Here is a failing test for the above situation. Next step is to wade through the code to figure out where to implement the fix. I wanted to get the failing test up here in case someone else with more knowledge of ActiveRecord wanted to fix it. :-)
-
Mike Gehard July 27th, 2010 @ 09:04 PM
One workaround for this is to remove the validates_presence_of :category and rely on a foreign key constraint on category_id (NOT NULL). This is OK as long as you are creating the Thing through the Category because you know that the Category exists because you just created it.
-
Neeraj Singh July 27th, 2010 @ 09:40 PM
- State changed from new to open
- Assigned user set to Neeraj Singh
- Tag set to rails 3, activerecord
I think it is a valid concern. I will take a look at it. It might be a bit tricky but will see how it goes.
-
Neeraj Singh August 10th, 2010 @ 02:57 PM
- State changed from open to resolved
There is another ticket open (can't find right now) which arges that :inverse_of should be the default. Code below fixes the issue
class Car < ActiveRecord::Base has_many :brakes, :inverse_of => :car def self.lab c = Car.new b = c.brakes.build puts b.car end end class Brake < ActiveRecord::Base belongs_to :car, :inverse_of => :brakes def self.lab end end > Car.lab #<Car:0x10203bc38>
-
Mike Gehard August 10th, 2010 @ 03:40 PM
Neeraj,
Can you point me in the direction of the commit that fixed this? I would like to take a look to see how you fixed it as a learning experience.
Thanks,
Mike
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>