diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index d35579b5d1..571dc6d21a 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,8 @@ *SVN* +* Provide Association Extensions access to the instance that the association is being accessed from. + Closes #4433 [josh@hasmanythrough.com] + * Update OpenBase adaterp's maintainer's email address. Closes #5176. [Derrick Spell] * Add a quick note about :select and eagerly included associations. [Rick] diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index ad28407e57..e1a0289039 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -232,6 +232,13 @@ module ActiveRecord # has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension] # end # + # Some extensions can only be made to work with knowledge of the association proxy's internals. + # Extensions can access relevant state using accessors on the association proxy: + # + # * +proxy_owner+ - Returns the object the association is part of. + # * +proxy_reflection+ - Returns the reflection object that describes the association. + # * +proxy_target+ - Returns the associated object for belongs_to and has_one, or the collection of associated objects for has_many and has_and_belongs_to_many. + # # === Association Join Models # # Has Many associations can be configured with the :through option to use an explicit join model to retrieve the data. This diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index adf7ad6ac6..ce0e154644 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -4,7 +4,7 @@ module ActiveRecord attr_reader :reflection alias_method :proxy_respond_to?, :respond_to? alias_method :proxy_extend, :extend - instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?|^proxy_respond_to\?|^proxy_extend|^send)/ } + instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_)/ } def initialize(owner, reflection) @owner, @reflection = owner, reflection @@ -12,6 +12,18 @@ module ActiveRecord reset end + def proxy_owner + @owner + end + + def proxy_reflection + @reflection + end + + def proxy_target + @target + end + def respond_to?(symbol, include_priv = false) proxy_respond_to?(symbol, include_priv) || (load_target && @target.respond_to?(symbol, include_priv)) end diff --git a/activerecord/test/associations_test.rb b/activerecord/test/associations_test.rb index c9a66f2efc..3667f71238 100755 --- a/activerecord/test/associations_test.rb +++ b/activerecord/test/associations_test.rb @@ -65,6 +65,29 @@ class AssociationsTest < Test::Unit::TestCase end end +class AssociationProxyTest < Test::Unit::TestCase + fixtures :authors, :posts + + def test_proxy_accessors + welcome = posts(:welcome) + assert_equal welcome, welcome.author.proxy_owner + assert_equal welcome.class.reflect_on_association(:author), welcome.author.proxy_reflection + welcome.author.class # force load target + assert_equal welcome.author, welcome.author.proxy_target + + david = authors(:david) + assert_equal david, david.posts.proxy_owner + assert_equal david.class.reflect_on_association(:posts), david.posts.proxy_reflection + david.posts.first # force load target + assert_equal david.posts, david.posts.proxy_target + + assert_equal david, david.posts_with_extension.testing_proxy_owner + assert_equal david.class.reflect_on_association(:posts_with_extension), david.posts_with_extension.testing_proxy_reflection + david.posts_with_extension.first # force load target + assert_equal david.posts_with_extension, david.posts_with_extension.testing_proxy_target + end +end + class HasOneAssociationsTest < Test::Unit::TestCase fixtures :accounts, :companies, :developers, :projects, :developers_projects diff --git a/activerecord/test/fixtures/author.rb b/activerecord/test/fixtures/author.rb index ec844f6238..a9102a269a 100644 --- a/activerecord/test/fixtures/author.rb +++ b/activerecord/test/fixtures/author.rb @@ -3,6 +3,17 @@ class Author < ActiveRecord::Base has_many :posts_with_comments, :include => :comments, :class_name => "Post" has_many :posts_with_categories, :include => :categories, :class_name => "Post" has_many :posts_with_comments_and_categories, :include => [ :comments, :categories ], :order => "posts.id", :class_name => "Post" + has_many :posts_with_extension, :class_name => "Post" do #, :extend => ProxyTestExtension + def testing_proxy_owner + proxy_owner + end + def testing_proxy_reflection + proxy_reflection + end + def testing_proxy_target + proxy_target + end + end has_many :comments, :through => :posts has_many :funky_comments, :through => :posts, :source => :comments