Multiple block args to ActiveRecord association proxy are splatted incorrectly
------------------------------------------------------------------------------

                 Key: JRUBY-4831
                 URL: http://jira.codehaus.org/browse/JRUBY-4831
             Project: JRuby
          Issue Type: Bug
    Affects Versions: JRuby 1.5
         Environment: Tested on Ubuntu 10.04 and Windows Server 2003
            Reporter: Colin Strasser
            Assignee: Thomas E Enebo


I added the following test cases to 
activerecord-2.3.8/test/cases/associations/has_many_associations_test.rb. These 
fail for JRuby but pass for MRI.

  def test_normal_method_call_in_association_proxy_with_multiple_block_args
    elem = nil
    Comment.all.each_with_index {|e, i| elem = e}
    assert_kind_of(Comment, elem)
    Post.find(:first).comments.each_with_index {|e, i| elem = e}
    assert_kind_of(Comment, elem) # FAILS in JRuby; elem is an Array
  end

  def test_instance_eval_in_association_proxy_with_multiple_block_args
    elem = nil
    Comment.all.each_with_index {|e, i| elem = e}
    assert_kind_of(Comment, elem)
    Post.find(:first).comments.each_with_index {|e, i| elem = e}
    assert_kind_of(Comment, elem) # FAILS in JRuby; elem is an Array
  end

The problem seems very similar to http://jira.codehaus.org/browse/JRUBY-2801 
(Incorrect argument splatting/array construction passing splatted args through 
a block that yields), but in the context of Object#send with a final &block 
argument rather than an explicit block.

Below is the commit that introduced the issue to ActiveRecord. Reverting the 
implementation of method_missing fixes my test cases but breaks the ones from 
the commit. I'm filing this as a JRuby bug rather than an ActiveRecord one 
since under MRI the code behaves as expected.


administra...@fivp-dev /c/dev/FIVP/rails/fivp/vendor/rails
$ git show
commit 2f1ded306728ce8ff614e09a113398328e7fe6ca
Author: Mat Brown <[email protected]>
Date:   Thu Oct 22 10:20:44 2009 -0400

    Fix instance_eval calls to association proxies

    In the current stable, 
ActiveRecord::Associations::AssociationProxy#method_missing calls yield() if a 
block is given, causing the block to always be evaluated in its calling 
context. However, in the case of instance_eval, correct behavior requires that 
the block be passed directly to the @target, rather than being evaluated inside 
a different block. Incidentally, this also simplifies the code slightly.
    
    [#3412 state:committed]
    
    Signed-off-by: Jeremy Kemper <[email protected]>

diff --git a/activerecord/lib/active_record/associations/association_proxy.rb 
b/activerecord/lib/active_record/associations/association_
index 3058e28..e1fce9a 100644
--- a/activerecord/lib/active_record/associations/association_proxy.rb
+++ b/activerecord/lib/active_record/associations/association_proxy.rb
@@ -208,14 +208,10 @@ module ActiveRecord
 
       private
         # Forwards any missing method call to the \target.
-        def method_missing(method, *args)
+        def method_missing(method, *args, &block)
           if load_target
             if @target.respond_to?(method)
-              if block_given?
-                @target.send(method, *args)  { |*block_args| 
yield(*block_args) }
-              else
-                @target.send(method, *args)
-              end
+              @target.send(method, *args, &block)
             else
               super
             end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb 
b/activerecord/test/cases/associations/has_many_associat
index eee80b2..94cdb52 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -1130,5 +1130,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
     client = firm.clients_using_primary_key.create!(:name => 'test')
     assert_equal firm.name, client.firm_name
   end
+
+  def test_normal_method_call_in_association_proxy
+    assert_equal 'Welcome to the weblog', Comment.all.map { |comment| 
comment.post }.first.title
+  end
+
+  def test_instance_eval_in_association_proxy
+    assert_equal 'Welcome to the weblog', Comment.all.map { |comment| 
comment.post }.first.instance_eval{title}
+  end
 end
 


-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: 
http://jira.codehaus.org/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply via email to