Skip to content

Commit efe121e

Browse files
authored
Merge pull request rails#27122 from kamipo/fix_unscope_with_subquery
Fix unscope with subquery
2 parents e0d0dc6 + bbf1f15 commit efe121e

File tree

2 files changed

+38
-14
lines changed

2 files changed

+38
-14
lines changed

activerecord/lib/active_record/relation/where_clause.rb

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ def merge(other)
2525
end
2626

2727
def except(*columns)
28-
WhereClause.new(
29-
predicates_except(columns),
30-
binds_except(columns),
31-
)
28+
WhereClause.new(*except_predicates_and_binds(columns))
3229
end
3330

3431
def or(other)
@@ -134,20 +131,35 @@ def invert_predicate(node)
134131
end
135132
end
136133

137-
def predicates_except(columns)
138-
predicates.reject do |node|
139-
case node
140-
when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
141-
subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
142-
columns.include?(subrelation.name.to_s)
134+
def except_predicates_and_binds(columns)
135+
except_binds = []
136+
binds_index = 0
137+
138+
predicates = self.predicates.reject do |node|
139+
except = \
140+
case node
141+
when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
142+
binds_contains = node.grep(Arel::Nodes::BindParam).size
143+
subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
144+
columns.include?(subrelation.name.to_s)
145+
end
146+
147+
if except && binds_contains > 0
148+
(binds_index...(binds_index + binds_contains)).each do |i|
149+
except_binds[i] = true
150+
end
151+
152+
binds_index += binds_contains
143153
end
154+
155+
except
144156
end
145-
end
146157

147-
def binds_except(columns)
148-
binds.reject do |attr|
149-
columns.include?(attr.name)
158+
binds = self.binds.reject.with_index do |_, i|
159+
except_binds[i]
150160
end
161+
162+
[predicates, binds]
151163
end
152164

153165
def predicates_with_wrapped_sql_literals

activerecord/test/cases/relations_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1935,6 +1935,18 @@ def test_presence
19351935
assert !Post.all.respond_to?(:by_lifo)
19361936
end
19371937

1938+
def test_unscope_with_subquery
1939+
p1 = Post.where(id: 1)
1940+
p2 = Post.where(id: 2)
1941+
1942+
assert_not_equal p1, p2
1943+
1944+
comments = Comment.where(post: p1).unscope(where: :post_id).where(post: p2)
1945+
1946+
assert_not_equal p1.first.comments, comments
1947+
assert_equal p2.first.comments, comments
1948+
end
1949+
19381950
def test_unscope_removes_binds
19391951
left = Post.where(id: Arel::Nodes::BindParam.new)
19401952
column = Post.columns_hash["id"]

0 commit comments

Comments
 (0)