Skip to content

Instantly share code, notes, and snippets.

@shannondoah
Last active January 19, 2024 22:02
Show Gist options
  • Save shannondoah/d2d576b019d5a3f667f02de6c2cac5a7 to your computer and use it in GitHub Desktop.
Save shannondoah/d2d576b019d5a3f667f02de6c2cac5a7 to your computer and use it in GitHub Desktop.
Extract correlated key patch demonstration - error is resolved with patch applied
# test-extract-correlated-key-with-patch.rb
# This is a stand-alone test case.
# Run it in your console with: `ruby test-extract-correlated-key-with-patch.rb`
# If you change the gem dependencies, run it with:
# `rm Gemfile* && ruby test-extract-correlated-key-with-patch.rb`
unless File.exist?('Gemfile')
File.write('Gemfile', <<-GEMFILE)
source 'https://rubygems.org'
# Rails master
gem 'rails', github: 'rails/rails', branch: '7-1-stable'
# Rails last release
# gem 'rails'
gem 'sqlite3'
gem 'ransack', github: 'activerecord-hackery/ransack'
GEMFILE
system 'bundle install'
end
require 'bundler'
Bundler.setup(:default)
require 'active_record'
require 'minitest/autorun'
require 'logger'
require 'ransack'
module RansackPatch
def self.included(base)
base.class_eval do
alias_method :extract_correlated_key, :extract_correlated_key_with_children_support
end
end
def extract_correlated_key_with_children_support(join_root)
case join_root
when Arel::Nodes::OuterJoin
# one of join_root.right/join_root.left is expected to be Arel::Nodes::On
if join_root.right.is_a?(Arel::Nodes::On)
extract_correlated_key(join_root.right.expr)
elsif join_root.left.is_a?(Arel::Nodes::On)
extract_correlated_key(join_root.left.expr)
else
raise 'Ransack encountered an unexpected arel structure'
end
when Arel::Nodes::Equality
pk = primary_key
if join_root.left == pk
join_root.right
elsif join_root.right == pk
join_root.left
end
when Arel::Nodes::And
# This is new to support nested children
if join_root.children.any?
join_root.children.each do |child|
eck = extract_correlated_key(child)
return eck unless eck.nil?
end
else
extract_correlated_key(join_root.left) || extract_correlated_key(join_root.right)
end
else # rubocop:disable Style/EmptyElse
# eg parent was Arel::Nodes::And and the evaluated side was one of
# Arel::Nodes::Grouping or MultiTenant::TenantEnforcementClause
nil
end
end
end
::Ransack::Adapters::ActiveRecord::Context.include RansackPatch
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)
# Display versions.
message = "Running test case with Ruby #{RUBY_VERSION}, Active Record #{
::ActiveRecord::VERSION::STRING}, Arel #{Arel::VERSION} and #{
::ActiveRecord::Base.connection.adapter_name}"
line = '=' * message.length
puts line, message, line
ActiveRecord::Schema.define do
create_table :users, force: true
create_table :posts, force: true do |t|
t.belongs_to :user
t.text :text
t.boolean :published, null: false, default: false
t.boolean :archived, null: false, default: false
end
end
class User < ActiveRecord::Base
has_many :published_posts, -> { where(published: true) }, class_name: "Post", inverse_of: :user
def self.ransackable_associations(auth_object = nil)
@ransackable_associations ||= %w[published_posts]
end
def self.ransackable_attributes(auth_object = nil)
@ransackable_attributes ||= column_names
end
end
class Post < ActiveRecord::Base
belongs_to :user
default_scope { where(archived: false) }
def self.ransackable_attributes(auth_object = nil)
@ransackable_attributes ||= column_names
end
end
class BugTest < Minitest::Test
def test_association_not_eq_query
not_eq_result = User.ransack({ published_posts_text_not_eq: "Some text" }).result
assert_empty(not_eq_result)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment