diff --git a/changelog/change_support_where_not_for_pluck_in_where.md b/changelog/change_support_where_not_for_pluck_in_where.md new file mode 100644 index 0000000000..17f2dac508 --- /dev/null +++ b/changelog/change_support_where_not_for_pluck_in_where.md @@ -0,0 +1 @@ +* [#1198](https://github.com/rubocop/rubocop-rails/issues/1198): Support `where.not` for `Rails/PluckInWhere`. ([@fatkodima][]) diff --git a/lib/rubocop/cop/mixin/active_record_helper.rb b/lib/rubocop/cop/mixin/active_record_helper.rb index ca5cfd6ab4..0bbe4e954c 100644 --- a/lib/rubocop/cop/mixin/active_record_helper.rb +++ b/lib/rubocop/cop/mixin/active_record_helper.rb @@ -99,7 +99,14 @@ def polymorphic?(belongs_to) def in_where?(node) send_node = node.each_ancestor(:send).first - send_node && WHERE_METHODS.include?(send_node.method_name) + return false unless send_node + + return true if WHERE_METHODS.include?(send_node.method_name) + + receiver = send_node.receiver + return false unless receiver&.send_type? + + send_node.method?(:not) && WHERE_METHODS.include?(receiver.method_name) end end end diff --git a/lib/rubocop/cop/rails/pluck_in_where.rb b/lib/rubocop/cop/rails/pluck_in_where.rb index 1da5967386..f88dde22d0 100644 --- a/lib/rubocop/cop/rails/pluck_in_where.rb +++ b/lib/rubocop/cop/rails/pluck_in_where.rb @@ -22,10 +22,12 @@ module Rails # @example # # bad # Post.where(user_id: User.active.pluck(:id)) + # Post.where.not(user_id: User.active.pluck(:id)) # # # good # Post.where(user_id: User.active.select(:id)) # Post.where(user_id: active_users.select(:id)) + # Post.where.not(user_id: active_users.select(:id)) # # @example EnforcedStyle: conservative (default) # # good diff --git a/spec/rubocop/cop/rails/pluck_in_where_spec.rb b/spec/rubocop/cop/rails/pluck_in_where_spec.rb index 030c73a00a..0a8836302c 100644 --- a/spec/rubocop/cop/rails/pluck_in_where_spec.rb +++ b/spec/rubocop/cop/rails/pluck_in_where_spec.rb @@ -17,6 +17,17 @@ RUBY end + it 'registers an offense and corrects when using `pluck` in `where.not` for constant' do + expect_offense(<<~RUBY) + Post.where.not(user_id: User.active.pluck(:id)) + ^^^^^ Use `select` instead of `pluck` within `where` query method. + RUBY + + expect_correction(<<~RUBY) + Post.where.not(user_id: User.active.select(:id)) + RUBY + end + it 'registers an offense and corrects when using `pluck` in `rewhere` for constant' do expect_offense(<<~RUBY) Post.rewhere('user_id IN (?)', User.active.pluck(:id))