Skip to content

Commit 8641f7f

Browse files
joshuay03byroot
authored andcommitted
[Fix rails#52530] Ensure all Nary children are evaluated when extracting attributes for WhereClause#merge
1 parent 9dfeb48 commit 8641f7f

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

activerecord/CHANGELOG.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,41 @@
1+
* Fix `#merge` with `#or` or `#and` and a mixture of attributes and SQL strings resulting in an incorrect query.
2+
3+
```ruby
4+
base = Comment.joins(:post).where(user_id: 1).where("recent = 1")
5+
puts base.merge(base.where(draft: true).or(Post.where(archived: true))).to_sql
6+
```
7+
8+
Before:
9+
10+
```SQL
11+
SELECT "comments".* FROM "comments"
12+
INNER JOIN "posts" ON "posts"."id" = "comments"."post_id"
13+
WHERE (recent = 1)
14+
AND (
15+
"comments"."user_id" = 1
16+
AND (recent = 1)
17+
AND "comments"."draft" = 1
18+
OR "posts"."archived" = 1
19+
)
20+
```
21+
22+
After:
23+
24+
```SQL
25+
SELECT "comments".* FROM "comments"
26+
INNER JOIN "posts" ON "posts"."id" = "comments"."post_id"
27+
WHERE "comments"."user_id" = 1
28+
AND (recent = 1)
29+
AND (
30+
"comments"."user_id" = 1
31+
AND (recent = 1)
32+
AND "comments"."draft" = 1
33+
OR "posts"."archived" = 1
34+
)
35+
```
36+
37+
*Joshua Young*
38+
139
* Make schema dumper to account for `ActiveRecord.dump_schemas` when dumping in `:ruby` format.
240

341
*fatkodima*

activerecord/lib/active_record/relation/where_clause.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,14 @@ def each_attributes
135135

136136
def extract_attribute(node)
137137
attr_node = nil
138-
Arel.fetch_attribute(node) do |attr|
139-
return if attr_node&.!= attr # all attr nodes should be the same
138+
139+
valid_attrs = Arel.fetch_attribute(node) do |attr|
140+
!attr_node || attr_node == attr # all attr nodes should be the same
141+
ensure
140142
attr_node = attr
141143
end
144+
return unless valid_attrs # all nested nodes should yield an attribute
145+
142146
attr_node
143147
end
144148

activerecord/test/cases/relation/where_clause_test.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,33 @@ class WhereClauseTest < ActiveRecord::TestCase
7474
assert_equal expected, a.merge(b)
7575
end
7676

77+
test "merge with or/and correctly handles SQL literals and attributes" do
78+
a = WhereClause.new([
79+
table["id"].eq(1),
80+
Arel::Nodes::Grouping.new(Arel.sql("foo = bar"))
81+
])
82+
b = (a + WhereClause.new([table["attr_1"].eq("val_1")])).or(
83+
WhereClause.new([table["attr_2"].eq("val_2")])
84+
)
85+
86+
expected = WhereClause.new([
87+
table["id"].eq(1),
88+
Arel::Nodes::Grouping.new(Arel.sql("foo = bar")),
89+
Arel::Nodes::Grouping.new(
90+
Arel::Nodes::Or.new([
91+
Arel::Nodes::And.new([
92+
table["id"].eq(1),
93+
Arel::Nodes::Grouping.new(Arel.sql("foo = bar")),
94+
table["attr_1"].eq("val_1")
95+
]),
96+
table["attr_2"].eq("val_2")
97+
])
98+
)
99+
])
100+
101+
assert_equal expected, a.merge(b)
102+
end
103+
77104
test "a clause knows if it is empty" do
78105
assert_empty WhereClause.empty
79106
assert_not_empty WhereClause.new([Arel.sql("anything")])

0 commit comments

Comments
 (0)