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.

Has_many :through _ids not passing conditions to SQL

#6680

Hi everyone,

First off, I love Rails. It's a fantastic framework.

So on to this possible bug...

Say I have a Book model with many authors through an AuthorAssignment model. The AuthorAssignment model also has an additional boolean column named featured.

class Book < ActiveRecord::Base
    has_many :author_assignments, :dependent => :destroy
    has_many :featured_authors, :through => :author_assignments, :conditions => "`author_assignments`.featured = 1"
end

Here is my problem:

When I call:

@book.featured_author_ids

The expected array of ids is incorrect. I get an array of all the author ids, not just the featured authors. The SQL query doesn't include the condition that 'author_assignments'.featured must be true.

SELECT `author_assignments`.author_id FROM `author_assignments` WHERE (`author_assignments`.book_id = 4)

On the other hand, when I fetch the @book.featured_authors records:

@book.featured_authors

The 'author_assignments'.featured condition is included in the SQL finder and the expected result for records is correct.

Thanks,
Chris

Reported by Chris Your · April 7th, 2011 @ 02:55 AM

State: new
Milestone: none
Assigned to: nobody
Importance: none

Activity

  1. Chris Your
    Chris Your

    I took a look at ActiveRecord-3.0.6 in associations.rb redefine_method("#{reflection.name.to_s.singularize}_ids") on line 1492. As far as I can see, the _ids method on the has_many :through association creates the finder on the through model like this (around line 1500:

    send(through.name).select("DISTINCT #{through.quoted_table_name}.#{primary_key}").map! { |r| r.send(primary_key) }
    

    I can easily add an if condition that looks for the :conditions option on the reflection and add the where conditions like this:

    if reflection.options[:conditions]
        send(through.name).select("DISTINCT #{through.quoted_table_name}.#{primary_key}").where(reflection.options[:conditions]).map! { |r| r.send(primary_key) }
    else
        send(through.name).select("DISTINCT #{through.quoted_table_name}.#{primary_key}").map! { |r| r.send(primary_key) }
    end
    

    But I'm sure there's a Rails way of doing this kind of thing.

    Any help to get this patched would be appreciated.

    Thanks,
    Chris

    April 8th, 2011 @ 04:21 PM

  2. Anatoliy Lysenko
    Anatoliy Lysenko

    I think you should look at master not v3.0.6 if you want to create a pathc.
    CollectionAssociation#reader_ids:

      column  = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}"
      scoped.select(column).except(:includes).map! do |record|
        record.send(reflection.association_primary_key)
      end
    

    Maybe scoped already has conditions?

    April 8th, 2011 @ 04:55 PM

  3. Chris Your
    Chris Your

    Hi Anatoliy,

    Thanks for the advice. I haven't contributed to Rails' source before...

    Scoped on the through object's reflection doesn't have the where conditions - the conditions are on the reflection object's reflection. If that makes sense.

    I wish I knew more about reflections and Arel. I'm learning as I dig through this source though. :)

    April 8th, 2011 @ 05:12 PM

  4. Chris Your
    Chris Your

    I took a look at Rails Master. Looks awesome. Lots of changes.

    I'll have to checkout master to see if the CollectionAssociation#reader_ids fixes this little bit of missing functionality in 3.0.6.

    April 8th, 2011 @ 06:22 PM