Created
January 19, 2012 01:08
-
-
Save avdi/1636945 to your computer and use it in GitHub Desktop.
Confused about class methods on association proxies in AR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
Can you update with it working with scoped?
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
?
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.
Here's a writeup of the solution: http://avdi.org/devblog/2012/01/19/activerecord-default-association-extensions/
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
So it turns out the answer is to use
scoped
.