Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

has_one through doesn't work when going through a collection association

#2912

When using alias_method to override a setter method for a has_one :through association, an undefined method error occurs when the alias method is called:

undefined method update_attributes' for #&lt;Class:0x3e4f298&gt;</code>
</pre>


This bug was introduced between Rails v2.2.1 and v2.2.2 in commit [a5609cd3cf3921cbd17b6314498318da7d522395] in the file has_one_through_association.rb.
This code sets the stage:
class Foo < ActiveRecord::Base
  has_many :foobars
  has_one :bar, :through => :foobars


alias_method :orig_bar=, :bar= def bar=(value)




Now just run this in your console to replicate the problem:
Foo.new.bar = Bar.new

self.orig_bar = value



end end
class Foobar < ActiveRecord::Base belongs_to :foo belongs_to :bar end
class Bar < ActiveRecord::Base end

Reported by Thomas Watson · July 15th, 2009 @ 10:43 PM

State: resolved
Milestone: 3.x
Assigned to: Aaron Patterson Aaron Patterson
Importance: none

Activity

  1. Jeremy Kemper
    Jeremy Kemper
    • Milestone changed from 2.x to 3.x

    May 4th, 2010 @ 06:48 PM

  2. Dan Pickett
    Dan Pickett
    • Tag changed from 2.2.2, activerecord, alias_method, associations, has_one_through, update_attributes to 2.2.2, activerecord, alias_method, associations, bugmash, has_one_through, update_attributes

    can a bugmasher review this against master?

    May 9th, 2010 @ 07:20 PM

  3. Lake
    Lake
    • Tag changed from 2.2.2, activerecord, alias_method, associations, bugmash, has_one_through, update_attributes to 2.2.2, 3.0.0.beta, activerecord, alias_method, associations, bugmash, has_one_through, update_attributes

    It appears that this happens even if we don't use alias_method...

    I have posted some code on github to try and help identify the issue. Check the readme for a quick overview.

    http://github.com/ldenman/rails-bm-ticket-2912

    May 14th, 2010 @ 10:49 PM

  4. Jeff Kreeftmeijer
    Jeff Kreeftmeijer
    • Tag changed from 2.2.2, 3.0.0.beta, activerecord, alias_method, associations, bugmash, has_one_through, update_attributes to 2.2.2, 3.0.0.beta, activerecord, alias_method, associations, bugmash, has_one_through, update_attributes, verified

    Verified with Thomas' code snippet against master and Lake's github repo (also, master).

    And here's a cleaned up version of Thomas' code:

    class Foo < ActiveRecord::Base
      has_many :foobars
      has_one :bar, :through => :foobars
    
      alias_method :orig_bar=, :bar=
      
      def bar=(value)
        self.orig_bar = value
      end
    end
    
    class Foobar < ActiveRecord::Base
      belongs_to :foo
      belongs_to :bar
    end
    
    class Bar < ActiveRecord::Base
    end
    

    And run this in the console:

    Foo.new.bar = Bar.new
    

    May 15th, 2010 @ 04:56 PM

  5. Jon Leighton
    Jon Leighton
    • Assigned user set to Aaron Patterson
    • Title changed from has_one through fails when setter is overridden using alias_method to has_one through doesn't work when going through a collection association
    • Tag changed from 2.2.2, 3.0.0.beta, activerecord, alias_method, associations, bugmash, has_one_through, update_attributes, verified to 2.2.2, 3.0.0.beta, activerecord, alias_method, associations, bugmash, has_one_through, patch, update_attributes

    This is not actually a problem with aliases at all.

    The problem is with putting a has_one association :through a collection (i.e. has_many). HasOneThroughAssociation#create_through_record looks up the through association, and expects it to be a single record. On this assumption it uses update_attributes, which obviously isn't defined on a collection. Hence the problem.

    My preferred solution is to make it invalid to put a has_one through a collection. If the user really wants to go through an association that could have many different records, they can explicitly add a has_one in place of the has_many, and use a combination of :order, :conditions etc to be specific about which record they want.

    I've attached a tested patch which prohibits has_one associations going through collections.

    December 19th, 2010 @ 02:19 PM

  6. blatyo
  7. Jon Leighton
    Jon Leighton
    • State changed from new to resolved

    December 23rd, 2010 @ 11:53 PM