Skip to content

Instantly share code, notes, and snippets.

@avdi
Created January 19, 2012 01:08
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save avdi/1636945 to your computer and use it in GitHub Desktop.
Save avdi/1636945 to your computer and use it in GitHub Desktop.
Confused about class methods on association proxies in AR
class Category < ActiveRecord::Base
belongs_to :sock
def self.foo
relation.build(:name => "bar")
end
end
class Sock < ActiveRecord::Base
has_many :categories
end
# Here is what I expect:
Category.foo # => #<Category id: nil name: "bar" sock_id: nil>
Sock.find(123).categories.foo # => #<Category id: nil name: "bar" sock_id: 123>
# What I actually get is:
Sock.find(123).categories.foo # => #<Category id: nil name: "bar" sock_id: nil>
# In other words, all methods in a class method should behave as if
# they are being called against the relation representing all records
# when called from the class itself, and as if being called against
# the relation representing the association when called against an
# association proxy.
# Instead, while the class method apparently gets tacked onto the
# association proxy, it behaves as if it is being called on the class,
# not on a specific association proxy.
# What am I missing here?
# And don't say the answer is to change Sock to this:
class Sock < ActiveRecord::Base
module CategoriesAssociation
def foo
relation.build(:name => "bar")
end
end
has_many :categories, :extend => CategoriesAssociation
end
# The whole point here is that all categories associations should get
# this method transparently, and it should Just Work.
@avdi
Copy link
Author

avdi commented Jan 19, 2012

So it turns out the answer is to use scoped.

@lukeholder
Copy link

Can you update with it working with scoped?

@jonleighton
Copy link

This should "just work". The method_missing in CollectionProxy basically does scoped { klass.send(method_name, ...) }.

I think maybe the problem is that you are calling relation. IIRC, relation is not public and shouldn't be called by users. Why don't you just define you method as:

  def self.foo
    build(:name => "bar")
  end

?

@avdi
Copy link
Author

avdi commented Jan 19, 2012

It does not Just Work. The class method doesn't have access to association proxy methods like #build; that just raises a no method error.

@avdi
Copy link
Author

avdi commented Jan 19, 2012

@troyk
Copy link

troyk commented Mar 9, 2012

Could this be related to issue I'm having: https://gist.github.com/2006057 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment