Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Backtracking association proxy chained methods

#1770

Bear with me, this is hard to explain, but I have a failing test case attached that demonstrates the problem (hopefully clearly enough)

When chaining association proxy methods together in such a way that you scope to a has_many, then follow a different belongs_to, and they turn around and come back on the has_many on the other side, you'll get different results depending on if you wrap part of of the query in a class method.

So, in the attached test, I start at authors(:david). David has_many categorizations. Each categorization belongs_to a category. And each category has many categorizations, some of which do not belong to David. I'm trying to find which of David's categorizations have siblings that may not belong to David.

The first way I check is to call... count_without_class_method = authors(:david).categorizations.find(:all).select {|cz| cz.category.categorizations.size > 1 }.size (The find(:all) is unnecessary, but included to make both samples as identical as possible)

For the second sample, I put everything everthing from find(:all) up to .size into a class method on Categorization, so that I can call... count_with_class_method = authors(:david).categorizations.that_have_siblings_with_common_category_parent.size

In theory, these two lines are both doing the exact same thing and should return the same result. However, the last line in the test fails because count_without_class_method != count_with_class_method

Reported by Jonathan Garvin · January 16th, 2009 @ 06:58 AM

State: stale
Milestone: 3.x
Assigned to: nobody
Importance: none

Activity

  1. Diego Algorta
    Diego Algorta

    Maybe you'd like to test if the patch in #1960 Make named_scopes remember the current scope when defined fixes this problem? Haven't had the time to test your diff there.

    February 17th, 2009 @ 06:37 PM

  2. Jonathan Garvin
    Jonathan Garvin

    Thanks for the suggestion Diego, but when I apply your patch, my test attached above still fails, and a new test fails ( test_named_scope(DefaultScopingTest) ).

    I don't think the issue I'm dealing with has is specific to named scopes but instead to associations proxies in general.

    February 18th, 2009 @ 02:30 AM

  3. Ryan Berdeen
    Ryan Berdeen

    In fact, the same problem occurs with named scopes and class methods, but it's the basically the inverse of #1960 Make named_scopes remember the current scope when defined (I thought they were dups at first, sorry for the confusion). Class methods called through association proxies and named scopes are both evaluated within the context of a with_scope. Adding

    
    named_scope :having_author_id, lambda { |author_id| {:conditions => ['`categorizations`.author_id = ?', author_id]} }
    

    to Categorization and then doing

    
    count_without_class_method = authors(:david).categorizations.find(:all).select {|cz| cz.category.categorizations.size > 1 }.size
        count_with_class_method = Categorization.having_author_id(authors(:david).id).that_have_siblings_with_common_category_parent.size
        assert_equal(count_without_class_method,count_with_class_method)
    

    gives the same result as accessing it through the association_collection.

    Either way, to get the result you want, just put the cz.category.categorizations.size within an exclusive scope:

    
    def that_have_siblings_with_common_category_parent
      find(:all).select {|cz| with_exclusive_scope {cz.category.categorizations.size > 1} }
    end
    
    With this, the test passes.
    

    February 18th, 2009 @ 07:00 AM

  4. Jonathan Garvin
    Jonathan Garvin

    Thanks Ryan, that's good to know. But I wonder if that should be considered the "correct" way to do that, or is that a hack/workaround/band-aid? I'm inclined to think it's a hack and we'd be better off solving the underlying problem (though, I don't know what that would be, yet). However, I'd rather be proven wrong before I waste any time trying to "fix" something that nobody else wants fixed. ;-)

    February 18th, 2009 @ 07:46 AM

  5. Jeremy Kemper
    Jeremy Kemper
    • Milestone changed from 2.x to 3.x

    May 4th, 2010 @ 06:48 PM

  6. Santiago Pastorino
    Santiago Pastorino
    • State changed from new to open
    • Importance changed from to

    This issue has been automatically marked as stale because it has not been commented on for at least three months.

    The resources of the Rails core team are limited, and so we are asking for your help. If you can still reproduce this error on the 3-0-stable branch or on master, please reply with all of the information you have about it and add "[state:open]" to your comment. This will reopen the ticket for review. Likewise, if you feel that this is a very important feature for Rails to include, please reply with your explanation so we can consider it.

    Thank you for all your contributions, and we hope you will understand this step to focus our efforts where they are most helpful.

    February 2nd, 2011 @ 04:42 PM

  7. Santiago Pastorino
    Santiago Pastorino
    • State changed from open to stale

    February 2nd, 2011 @ 04:42 PM