Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP


building a has_many :through with :conditions #161

the8472 opened this Issue · 7 comments

3 participants


I think i've run into a bug:

class A < ActiveRecord::Base
  has_many :a_b_mappings
  has_many :b_assoc, :through => :a_b_mappings, :conditions => {:context => "foo"}

#<B id: nil, context: nil>

context should be "foo".

After stepping through the code I found that find_equality_predicates in the 3.1/relation-extensions.rb only checks for arel nodes but the nodes array which is passed as argument actually contains 2 equality nodes and a raw sql string: "b"."context" = 'foo', which obviously is the condition we actually want.


Hm. What version of Rails/Squeel? Have you tried against Squeel master?

Does stock AR behave "correctly" in this situation? It seems odd to me, since creating a b_assoc devoid of its a_b_mapping context would be unable to correctly populate other essential values, like a b_id to relate back to a_b_mappings.

  • rails 3.2.8
  • ruby 1.9.3
  • squeel 1.0.9
  • haven't tried master.

As for the other essential values: :inverse_of in the join table relations on B and ABMappings allows the association ids to be populated, which already works. Rails does some magic by traversing the chain of through associations to fetch all the conditions there, so it should work in vanilla rails. See for an example. Although I have yet have to test it myself.


Maybe. I'm suspicious that it won't work, after reading the Rails source, which works very similarly to my implementation, minus the lazy evaluation of hashes. That being said, I haven't set up a test to try.


Seems like you're right, with vanilla rails 3.2.8:

class A < ActiveRecord::Base
  has_many :a_b_mappings, :inverse_of => :a
  has_many :b, :through => :a_b_mappings, :source => :b, :conditions => {:context => "foo"}

class B < ActiveRecord::Base
  has_many :a_b_mappings, :inverse_of => :b

class ABMapping < ActiveRecord::Base
  self.table_name = :a_b_mappings
  belongs_to :a, :inverse_of => :a_b_mappings
  belongs_to :b, :inverse_of => :a_b_mappings

puts A.first.b.create.tap{|b| puts b.inspect}.a_b_mappings.inspect
# #<B id: 3, context: nil> 
# [#<ABMapping id: 2, a_id: 1, b_id: 2>]

It creates the through-association but does not set the defaults. Meh. And I bet this will never get fixed in rails.

@the8472 the8472 closed this

This means I can't use sifters in the condition value ?


Conditions should only be simple hashes to allow rails to build the join models


:+1: thank you guys! I consider squeel a majestic gem. Kudooosss!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.