This project is archived and is in readonly mode.

#3510 ✓resolved
Bryan Larsen

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

    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
  • Mike Gehard

    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

    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

    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

    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

  • Neeraj Singh

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>

Attachments

Pages