From 90e4d2325e3018530d39a095f97c9c0927465736 Mon Sep 17 00:00:00 2001 From: Alessandro Rodi Date: Fri, 12 Nov 2021 15:08:47 +0100 Subject: [PATCH 1/2] Debug exists subquery --- lib/cancan.rb | 1 + .../strategies/exists_subquery.rb | 22 +++++++++++++++++++ .../accessible_by_has_many_through_spec.rb | 3 ++- 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 lib/cancan/model_adapters/strategies/exists_subquery.rb diff --git a/lib/cancan.rb b/lib/cancan.rb index 76d72af77..9ad8e823b 100644 --- a/lib/cancan.rb +++ b/lib/cancan.rb @@ -24,4 +24,5 @@ require 'cancan/model_adapters/strategies/base' require 'cancan/model_adapters/strategies/left_join' require 'cancan/model_adapters/strategies/subquery' + require 'cancan/model_adapters/strategies/exists_subquery' end diff --git a/lib/cancan/model_adapters/strategies/exists_subquery.rb b/lib/cancan/model_adapters/strategies/exists_subquery.rb new file mode 100644 index 000000000..6b0f18661 --- /dev/null +++ b/lib/cancan/model_adapters/strategies/exists_subquery.rb @@ -0,0 +1,22 @@ +module CanCan + module ModelAdapters + class Strategies + class ExistsSubquery < Base + def execute! + model_class.where(joined_alias_exists_subquery_inner_query.arel.exists) + end + + def joined_alias_exists_subquery_inner_query + model_class + .select('1') + .left_joins(joins) + .where(*where_conditions) + .where( + "#{quoted_table_name}.#{quoted_primary_key} = " \ + "#{quoted_aliased_table_name}.#{quoted_primary_key}" + ) + end + end + end + end +end diff --git a/spec/cancan/model_adapters/accessible_by_has_many_through_spec.rb b/spec/cancan/model_adapters/accessible_by_has_many_through_spec.rb index 3f5eb2124..85042b367 100644 --- a/spec/cancan/model_adapters/accessible_by_has_many_through_spec.rb +++ b/spec/cancan/model_adapters/accessible_by_has_many_through_spec.rb @@ -89,7 +89,8 @@ class Editor < ActiveRecord::Base if CanCan::ModelAdapters::ActiveRecordAdapter.version_greater_or_equal?('5.0.0') describe 'selecting custom columns' do it 'extracts custom columns correctly' do - posts = Post.accessible_by(ability).where(published: true).select('title as mytitle') + posts = Post.where(title: 'a').accessible_by(ability).where(published: true).select('title as mytitle') + puts posts.to_sql expect(posts[0].mytitle).to eq 'post1' end end From e1a749fb0d170116e964f788de591d30e094cb0f Mon Sep 17 00:00:00 2001 From: Alessandro Rodi Date: Fri, 12 Nov 2021 15:18:30 +0100 Subject: [PATCH 2/2] Add more code --- cancancan.gemspec | 1 + lib/cancan/config.rb | 12 +++++++++--- lib/cancan/model_adapters/strategies/subquery.rb | 8 +------- spec/spec_helper.rb | 1 + 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cancancan.gemspec b/cancancan.gemspec index 95005509d..f3a7647a3 100644 --- a/cancancan.gemspec +++ b/cancancan.gemspec @@ -26,4 +26,5 @@ Gem::Specification.new do |s| s.add_development_dependency 'rake', '~> 10.1', '>= 10.1.1' s.add_development_dependency 'rspec', '~> 3.2', '>= 3.2.0' s.add_development_dependency 'rubocop', '~> 0.63.1' + s.add_development_dependency 'byebug', '~> 9.0', '>= 9.0.0' end diff --git a/lib/cancan/config.rb b/lib/cancan/config.rb index a9106526b..4566718ab 100644 --- a/lib/cancan/config.rb +++ b/lib/cancan/config.rb @@ -3,10 +3,16 @@ module CanCan def self.valid_accessible_by_strategies strategies = [:left_join] - strategies << :subquery unless does_not_support_subquery_strategy? + unless does_not_support_subquery_strategy? + strategies.push(*subquery_strategies) + end strategies end + def self.subquery_strategies + [:subquery, :exists_subquery] + end + # Determines how CanCan should build queries when calling accessible_by, # if the query will contain a join. The default strategy is `:subquery`. # @@ -40,8 +46,8 @@ def self.default_accessible_by_strategy def self.accessible_by_strategy=(value) validate_accessible_by_strategy!(value) - if value == :subquery && does_not_support_subquery_strategy? - raise ArgumentError, 'accessible_by_strategy = :subquery requires ActiveRecord 5 or newer' + if subquery_strategies.include?(value) && does_not_support_subquery_strategy? + raise ArgumentError, "accessible_by_strategy = #{value} requires ActiveRecord 5 or newer" end @accessible_by_strategy = value diff --git a/lib/cancan/model_adapters/strategies/subquery.rb b/lib/cancan/model_adapters/strategies/subquery.rb index cc7019aa4..569590d8a 100644 --- a/lib/cancan/model_adapters/strategies/subquery.rb +++ b/lib/cancan/model_adapters/strategies/subquery.rb @@ -3,13 +3,7 @@ module ModelAdapters class Strategies class Subquery < Base def execute! - build_joins_relation_subquery(where_conditions) - end - - def build_joins_relation_subquery(where_conditions) - inner = model_class.unscoped do - model_class.left_joins(joins).where(*where_conditions) - end + inner = model_class.unscoped { model_class.left_joins(joins).where(*where_conditions) } model_class.where(model_class.primary_key => inner) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7f2a4ab8c..a16b6bd1c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,6 +5,7 @@ Bundler.require +require 'byebug' require 'matchers' require 'cancan/matchers'