This project is archived and is in readonly mode.

#1492 ✓invalid
joshsmoore (at gmail)

Models not loaded properly when using named_scope

Reported by joshsmoore (at gmail) | November 29th, 2008 @ 02:28 AM | in 2.x

This bug is a little complicated to explain. So I will introduce my program and then at the end I will introduce what is going wrong.

I have two models note and label. The models look like this


class Note < ActiveRecord::Base
  has_and_belongs_to_many :labels


  named_scope :has_labels, lambda { |label| {:include => :labels,
    :conditions => ['labels.label =?', label]}}
end

class Label < ActiveRecord::Base
  has_and_belongs_to_many :notes
end

These are what is in my fixtures. Notes


one:
  title: note1
  body: this is a test note 1

two:
  title: note 2
  body: sthis is  the second note
  labels: test, test2

three:
  title: note 3
  body: I like this note
  labels: test, test4

Labels



test:
  label: test

test_1:
  label: test_1

test2:
  label: test2

test4:
  label: test 4

The problem is when I run this test


  def test_load_labels
    n = Note.find_by_title('note 3')
    n2 = Note.has_labels(['test 4']).first

    assert_equal n.labels.count, n2.labels.count
    assert_equal n.title, n2.title
    assert_equal n.labels.collect{|label| label.label}.join,
      n2.labels.collect{|label| label.label}.join
  end

I would expect all these assertions to match (because the objects are identical). However, the last one does not. The first assertion passes (so it thinks that both objects have the same number of labels). But, the last one fails with this comment: <"testtest 4"> expected but was <"test 4">. I am assuming this is a bug. If not can somebody please tell me why it works this why?

System Information: Rails: 2.2.2 Ruby: jruby 1.1.5 or Ruby 1.8.6-p111 (have tested both) Database: sqlite3 or MySQL (have tested both) OS: Ubuntu 8.04

Comments and changes to this ticket

  • joshsmoore (at gmail)

    joshsmoore (at gmail) November 29th, 2008 @ 04:52 AM

    I just confirmed this still happens in edge rails.

  • Frederick Cheung

    Frederick Cheung December 15th, 2008 @ 11:22 PM

    This is an odd interaction between named scopes and join based includes.

    The :include means that your select looks like

    
    SELECT ... FROM notes
    LEFT OUTER JOIN labels ...
    

    For the case you gave this would return two rows (because the note in question has 2 notes), however the first on the scope is limiting the select to just one row - so you only get one label back.

  • Frederick Cheung

    Frederick Cheung December 16th, 2008 @ 12:04 AM

    • State changed from “new” to “invalid”

    D'oh, read too quickly. The start of what I said was correct, the problem you get is that the conditions (labels.label = '...') applies to the whole query.

    The named scope here is irrelevant,

    
    Note.find :all, :include => :labels, :conditions =>['labels.label =?', 'test']
    

    will exhibit the same problem: all of the notes loaded in this way will have exactly one label, because the conditions prevent any other labels from being loaded by the big join query.

    What this boils down to is that :include with :conditions on the included table has dubious semantics. If you don't actually care about the eager loading,

    
    named_scope :has_labels, lambda { |label| {:joins => :labels, :conditions => ['labels.label =?', label]}}
    

    would select the correct notes.

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

People watching this ticket

Pages