This project is archived and is in readonly mode.
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) November 29th, 2008 @ 04:52 AM
I just confirmed this still happens in edge rails.
-
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 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>