From 2cc9b919c330864c5bede88f102f9020980f57ed Mon Sep 17 00:00:00 2001 From: Qian Chen <> Date: Thu, 21 Jun 2018 15:50:11 +0800 Subject: [PATCH] fix undefined method eq for Arel::Nodes::Equality by deep call left --- lib/ransack/adapters/active_record/context.rb | 14 ++++++- .../adapters/active_record/context_spec.rb | 41 +++++++++++++++++++ spec/support/schema.rb | 6 +++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/lib/ransack/adapters/active_record/context.rb b/lib/ransack/adapters/active_record/context.rb index 201dc70..122c981 100644 --- a/lib/ransack/adapters/active_record/context.rb +++ b/lib/ransack/adapters/active_record/context.rb @@ -163,7 +163,7 @@ module Ransack def build_correlated_subquery(association) join_constraints = extract_joins(association) join_root = join_constraints.shift - correlated_key = join_root.right.expr.left + correlated_key = extract_correlated_key(join_root) subquery = Arel::SelectManager.new(association.base_klass) subquery.from(join_root.left) subquery.project(correlated_key) @@ -179,6 +179,18 @@ module Ransack private + def extract_correlated_key(join_root) + correlated_key = join_root.right.expr.left + + if correlated_key.is_a? Arel::Nodes::And + correlated_key = correlated_key.left.left + elsif correlated_key.is_a? Arel::Nodes::Equality + correlated_key = correlated_key.left + else + correlated_key + end + end + def get_parent_and_attribute_name(str, parent = @base) attr_name = nil diff --git a/spec/ransack/adapters/active_record/context_spec.rb b/spec/ransack/adapters/active_record/context_spec.rb index a6aa3fc..282e381 100644 --- a/spec/ransack/adapters/active_record/context_spec.rb +++ b/spec/ransack/adapters/active_record/context_spec.rb @@ -40,6 +40,47 @@ module Ransack end end + describe '#build_correlated_subquery' do + it 'build correlated subquery for Root STI model' do + search = Search.new(Person, { articles_title_not_eq: 'some_title' }, context: subject) + attribute = search.conditions.first.attributes.first + constraints = subject.build_correlated_subquery(attribute.parent).constraints + constraint = constraints.first + + expect(constraints.length).to eql 1 + expect(constraint.left.name).to eql 'person_id' + expect(constraint.left.relation.name).to eql 'articles' + expect(constraint.right.name).to eql 'id' + expect(constraint.right.relation.name).to eql 'people' + end + + it 'build correlated subquery for Child STI model when predicate is not_eq' do + search = Search.new(Person, { story_articles_title_not_eq: 'some_title' }, context: subject) + attribute = search.conditions.first.attributes.first + constraints = subject.build_correlated_subquery(attribute.parent).constraints + constraint = constraints.first + + expect(constraints.length).to eql 1 + expect(constraint.left.relation.name).to eql 'articles' + expect(constraint.left.name).to eql 'person_id' + expect(constraint.right.relation.name).to eql 'people' + expect(constraint.right.name).to eql 'id' + end + + it 'build correlated subquery for Child STI model when predicate is eq' do + search = Search.new(Person, { story_articles_title_not_eq: 'some_title' }, context: subject) + attribute = search.conditions.first.attributes.first + constraints = subject.build_correlated_subquery(attribute.parent).constraints + constraint = constraints.first + + expect(constraints.length).to eql 1 + expect(constraint.left.relation.name).to eql 'articles' + expect(constraint.left.name).to eql 'person_id' + expect(constraint.right.relation.name).to eql 'people' + expect(constraint.right.name).to eql 'id' + end + end + describe 'sharing context across searches' do let(:shared_context) { Context.for(Person) } diff --git a/spec/support/schema.rb b/spec/support/schema.rb index 348be66..74d83bc 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -29,6 +29,8 @@ class Person < ActiveRecord::Base belongs_to :parent, class_name: 'Person', foreign_key: :parent_id has_many :children, class_name: 'Person', foreign_key: :parent_id has_many :articles + has_many :story_articles + has_many :published_articles, ->{ where(published: true) }, class_name: "Article" has_many :comments @@ -136,6 +138,9 @@ class Article < ActiveRecord::Base default_scope { where("'default_scope' = 'default_scope'") } end +class StoryArticle < Article +end + class Recommendation < ActiveRecord::Base belongs_to :person belongs_to :target_person, class_name: 'Person' @@ -194,6 +199,7 @@ module Schema t.string :title t.text :subject_header t.text :body + t.string :type t.boolean :published, default: true end