Reputation: 3265
I'm using Rails 5.0.7.1, and I see in the docs that my CollectionProxy instance should have access to an "@owner" instance variable:
Association proxies in Active Record are middlemen between the object that holds the association, known as the @owner, and the actual associated object, known as the @target. The kind of association any proxy is about is available in @reflection. That's an instance of the class ActiveRecord::Reflection::AssociationReflection.
the association proxy in blog.posts has the object in blog as @owner, the collection of its posts as @target, and the @reflection object represents a :has_many macro.
This class delegates unknown methods to @target via method_missing.
In my Rails app, I've got the following (rather unrealistic) test code:
class Post < ApplicationRecord
has_many :comments do
def number_five
if owner.is_a? Post
Comment.where(id: 5, post_id: self.id)
end
end
end
end
class Comment < ApplicationRecord
belongs_to :post
end
When I call Post.last.commments.number_five
, I get the following error:
NameError (undefined local variable or method `owner' for #
<Comment::ActiveRecord_Associations_CollectionProxy:0x00007fcbb9106120>)
When I add byebug
to the line in between def number_five
and owner.is_a? Post
, and I check the value of self
, I see it's ActiveRecord::Associations::CollectionProxy
, so I think I'm calling owner
in a scope where it should be defined.
I've tried Post.last.comments.instance_variables
, and I don't see :@owner
, only the following:
[:@association, :@klass, :@table, :@values, :@offsets,
:@loaded, :@predicate_builder, :@scope]
I've also tried the following:
comments = Post.last.comments
def comments.get_owner
self.owner
end
This returns the same NameError
as above.
For what it's worth, when I run Post.last.comments.class
, I see it's Comment::ActiveRecord_Associations_CollectionProxy
.
Given how the docs read, I'd expect to be able to call either Post.last.comments.owner
or @owner
from within Post.last.comments
(both of which I've tried), and have it return the value of Post.last
. Is my expectation incorrect, or is my code wrong, or is it something else entirely?
Upvotes: 2
Views: 435
Reputation: 434755
The documentation is a little confusing. I remember having to spend a few hours guessing, reading the Rails source, and experimenting to figure this out the first time I need to get outside the association from an extension method.
owner
is what you're after but that's a method on the association and you get the association via proxy_association
(which is just an accessor method for @association
):
has_many :comments do
def number_five
if proxy_association.owner.is_a? Post
#...
end
end
end
I'm not sure if this is the "right" or "official" way to do this but this is what I've been doing since Rails 4.
Upvotes: 3