Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## 2.4.0.findy.1 2026-05-13
* [Findy fork] Guard `visit obj.alias` calls in `MultiTenant::ArelVisitorsDepthFirst` with `respond_to?(:alias)` so the visitor works on Rails 8.1, which removed the `alias` attribute from `Arel::Nodes::Function` (and its `Avg`/`Exists`/`Max`/`Min`/`Sum`/`NamedFunction`/`Count` subclasses). Preserves existing behavior on Rails 6/7/8.0.

## 2.4.0 2023-09-22
* Adds citus 12 to test matrix (#210)
* Adds Support for rails 7.1 (#208)
Expand Down
6 changes: 3 additions & 3 deletions lib/activerecord-multi-tenant/arel_visitors_depth_first.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def unary(obj)

def function(obj)
visit obj.expressions
visit obj.alias
visit obj.alias if obj.respond_to?(:alias)
visit obj.distinct
end
alias visit_Arel_Nodes_Avg function
Expand All @@ -54,12 +54,12 @@ def visit_Arel_Nodes_NamedFunction(obj)
visit obj.name
visit obj.expressions
visit obj.distinct
visit obj.alias
visit obj.alias if obj.respond_to?(:alias)
end

def visit_Arel_Nodes_Count(obj)
visit obj.expressions
visit obj.alias
visit obj.alias if obj.respond_to?(:alias)
visit obj.distinct
end

Expand Down
2 changes: 1 addition & 1 deletion lib/activerecord-multi-tenant/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module MultiTenant
VERSION = '2.4.0'
VERSION = '2.4.0.findy.1'
end
51 changes: 51 additions & 0 deletions spec/activerecord-multi-tenant/arel_visitors_depth_first_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

require 'arel'
require 'activerecord-multi-tenant/arel_visitors_depth_first'

describe MultiTenant::ArelVisitorsDepthFirst do
let(:visited) { [] }
let(:visitor) { described_class.new(->(node) { visited << node }) }
let(:table) { Arel::Table.new(:projects) }
let(:expr) { table[:id] }

describe 'function nodes' do
%i[Avg Exists Max Min Sum].each do |const_name|
it "traverses Arel::Nodes::#{const_name} without raising" do
node = Arel::Nodes.const_get(const_name).new([expr])

expect { visitor.accept(node) }.not_to raise_error
expect(visited).to include(expr)
end
end
end

describe 'Arel::Nodes::NamedFunction' do
it 'traverses the node without raising' do
node = Arel::Nodes::NamedFunction.new('coalesce', [expr])

expect { visitor.accept(node) }.not_to raise_error
expect(visited).to include(expr)
end

it 'visits the alias when the node still exposes #alias (Rails <= 8.0)' do
node = Arel::Nodes::NamedFunction.new('coalesce', [expr])
skip 'Arel::Nodes::NamedFunction#alias was removed in this Rails version' unless node.respond_to?(:alias)

node.as('id_alias')
visitor.accept(node)

literals = visited.grep(Arel::Nodes::SqlLiteral).map(&:to_s)
expect(literals).to include('id_alias')
end
end

describe 'Arel::Nodes::Count' do
it 'traverses the node without raising' do
node = Arel::Nodes::Count.new([expr])

expect { visitor.accept(node) }.not_to raise_error
expect(visited).to include(expr)
end
end
end
Loading