Skip to content

Commit 4566158

Browse files
clgiovannelligiovannelli
authored andcommitted
fix: #1411
1 parent 2d56e78 commit 4566158

File tree

4 files changed

+55
-2
lines changed

4 files changed

+55
-2
lines changed

lib/ransack/nodes/condition.rb

+12-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,14 @@ def negative?
286286
def arel_predicate
287287
predicate = attributes.map { |attribute|
288288
association = attribute.parent
289-
if negative? && attribute.associated_collection?
289+
parent_table = association.table
290+
291+
if parent_table.class == Arel::Nodes::TableAlias
292+
left = parent_table.left.name
293+
parent_table.right = left if !ActiveRecord::Base.connection.table_exists?(left)
294+
end
295+
296+
if negative? && attribute.associated_collection? && not_nested_condition(attribute, parent_table)
290297
query = context.build_correlated_subquery(association)
291298
context.remove_association(association)
292299
if self.predicate_name == 'not_null' && self.value
@@ -313,6 +320,10 @@ def arel_predicate
313320
predicate
314321
end
315322

323+
def not_nested_condition(attribute, parent_table)
324+
parent_table.class != Arel::Nodes::TableAlias && attribute.name.starts_with?(parent_table.name)
325+
end
326+
316327
private
317328

318329
def combinator_method

spec/ransack/adapters/active_record/base_spec.rb

+35
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,41 @@ module ActiveRecord
191191
end
192192
end
193193

194+
context 'negative conditions on related object with HABTM associations' do
195+
let(:medieval) { Tag.create!(name: 'Medieval') }
196+
let(:fantasy) { Tag.create!(name: 'Fantasy') }
197+
let(:arthur) { Article.create!(title: 'King Arthur') }
198+
let(:marco) { Article.create!(title: 'Marco Polo') }
199+
let(:comment_arthur) { marco.comments.create!(body: 'King Arthur comment') }
200+
let(:comment_marco) { arthur.comments.create!(body: 'Marco Polo comment') }
201+
202+
before do
203+
comment_arthur.tags << medieval
204+
comment_marco.tags << fantasy
205+
end
206+
207+
it 'removes redundant joins from top query' do
208+
s = Article.ransack(comments_tags_name_not_eq: "Fantasy")
209+
sql = s.result.to_sql
210+
expect(sql).to include('LEFT OUTER JOIN')
211+
end
212+
213+
it 'handles != for single values' do
214+
s = Article.ransack(comments_tags_name_not_eq: "Fantasy")
215+
articles = s.result.to_a
216+
expect(articles).to include marco
217+
expect(articles).to_not include arthur
218+
end
219+
220+
it 'handles NOT IN for multiple attributes' do
221+
s = Article.ransack(comments_tags_name_not_in: ["Fantasy", "Scifi"])
222+
articles = s.result.to_a
223+
224+
expect(articles).to include marco
225+
expect(articles).to_not include arthur
226+
end
227+
end
228+
194229
context 'negative conditions on self-referenced associations' do
195230
let(:pop) { Person.create!(name: 'Grandpa') }
196231
let(:dad) { Person.create!(name: 'Father') }

spec/ransack/search_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ module Ransack
178178
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
179179
# ) ORDER BY "people"."id" DESC
180180

181-
pending("spec should pass, but I do not know how/where to fix lib code")
181+
#pending("spec should pass, but I do not know how/where to fix lib code")
182182
s = Search.new(Person, published_articles_title_not_eq: 'Test')
183183
expect(s.result.to_sql).to include 'default_scope'
184184
expect(s.result.to_sql).to include 'published'

spec/support/schema.rb

+7
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,14 @@ class Article < ::Article
220220
class Comment < ApplicationRecord
221221
belongs_to :article
222222
belongs_to :person
223+
has_and_belongs_to_many :tags
223224

224225
default_scope { where(disabled: false) }
225226
end
226227

227228
class Tag < ApplicationRecord
228229
has_and_belongs_to_many :articles
230+
has_and_belongs_to_many :comments
229231
end
230232

231233
class Note < ApplicationRecord
@@ -298,6 +300,11 @@ def self.create
298300
t.integer :tag_id
299301
end
300302

303+
create_table :comments_tags, force: true, id: false do |t|
304+
t.integer :comment_id
305+
t.integer :tag_id
306+
end
307+
301308
create_table :notes, force: true do |t|
302309
t.integer :notable_id
303310
t.string :notable_type

0 commit comments

Comments
 (0)