diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index b79b9a87c699cc535e2795ce284805c775b075da..38f8bfced93c3296aea732006026bc5a4edc94a8 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,11 @@ +* Fix: joins association, with defined in the scope block constraints by using several + where constraints and at least of them is not `Arel::Nodes::Equality`, + generates invalid SQL expression. + + Fixes: #11963 + + *Paul Nikitochkin* + * Re-use `order` argument pre-processing for `reorder`. *Paul Nikitochkin* diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 1c6ea94c0bf010d8fc6ca74c6783d30b1fcaba90..5d0df3258210983472a430312490946f1f7f1ba2 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -882,14 +882,13 @@ def custom_join_ast(table, joins) end def collapse_wheres(arel, wheres) - equalities = wheres.grep(Arel::Nodes::Equality) - - arel.where(Arel::Nodes::And.new(equalities)) unless equalities.empty? - - (wheres - equalities).each do |where| + predicates = wheres.map do |where| + next where if ::Arel::Nodes::Equality === where where = Arel.sql(where) if String === where - arel.where(Arel::Nodes::Grouping.new(where)) + Arel::Nodes::Grouping.new(where) end + + arel.where(Arel::Nodes::And.new(predicates)) if predicates.present? end def build_where(opts, other = []) diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb index de47a576c6d946e9ad8eb4d9ef7b28009084dd49..9fe5ff50d908b999dcad55f5c8f0a0e809476767 100644 --- a/activerecord/test/cases/associations/inner_join_association_test.rb +++ b/activerecord/test/cases/associations/inner_join_association_test.rb @@ -41,6 +41,11 @@ def test_join_conditions_added_to_join_clause assert_no_match(/WHERE/i, sql) end + def test_join_association_conditions_support_string_and_arel_expressions + assert_equal 0, Author.joins(:welcome_posts_with_comment).count + assert_equal 1, Author.joins(:welcome_posts_with_comments).count + end + def test_join_conditions_allow_nil_associations authors = Author.includes(:essays).where(:essays => {:id => nil}) assert_equal 2, authors.count diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index feb828de31ec4e21f6196c5c5a12a2f885e92fd6..5d203893310d620019f6722d2063829b880c78f1 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -31,6 +31,13 @@ def ratings has_many :thinking_posts, -> { where(:title => 'So I was thinking') }, :dependent => :delete_all, :class_name => 'Post' has_many :welcome_posts, -> { where(:title => 'Welcome to the weblog') }, :class_name => 'Post' + has_many :welcome_posts_with_comment, + -> { where(title: 'Welcome to the weblog').where('comments_count = ?', 1) }, + class_name: 'Post' + has_many :welcome_posts_with_comments, + -> { where(title: 'Welcome to the weblog').where(Post.arel_table[:comments_count].gt(0)) }, + class_name: 'Post' + has_many :comments_desc, -> { order('comments.id DESC') }, :through => :posts, :source => :comments has_many :limited_comments, -> { limit(1) }, :through => :posts, :source => :comments has_many :funky_comments, :through => :posts, :source => :comments