This project is archived and is in readonly mode.

#6680 new
Chris Your

Has_many :through _ids not passing conditions to SQL

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

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

Comments and changes to this ticket

  • Chris Your

    Chris Your April 8th, 2011 @ 04:21 PM

    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

  • Anatoliy Lysenko

    Anatoliy Lysenko April 8th, 2011 @ 04:55 PM

    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?

  • Chris Your

    Chris Your April 8th, 2011 @ 05:12 PM

    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. :)

  • Chris Your

    Chris Your April 8th, 2011 @ 06:22 PM

    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.

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>

Pages