Skip to content
Draft
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
20 changes: 15 additions & 5 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
require:
- ./lib/rubocop/cop/custom/explicit_select.rb

Custom/ExplicitSelect:
Enabled: true

AllCops:
NewCops: enable
Exclude:
- "db/schema.rb"
- "db/migrate.rb"
- "db/structure.sql"
- "Gemfile"
- "lib/tasks/*.rake"
Expand All @@ -11,9 +17,13 @@ AllCops:
- "config/environments/development.rb"
- "config/environments/production.rb"
- "spec/spec_helper.rb"
- 'tmp/**/*'
- 'docker/**/*'
- 'log/**/*'
- '.circleci/**/*'
- '.git/**/*'
SuggestExtensions: false
NewCops: enable

Style/Documentation:
Enabled: false

# Disable suggestions for rubocop-rails for now
AllCops:
SuggestExtensions: false
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,13 @@ bin/rails server
Once that's running, visit <http://localhost:3000/pghero> in your browser to see it.

![Screenshot of PgHero for Rideshare](https://i.imgur.com/VduvxSK.png)

## Rubocop

- <https://danielabaron.me/blog/add-rubocop-to-legacy-project/>
- Custom cop for detecting missing explicit select

```
app/controllers/api/trip_requests_controller.rb:3:5: C: [Correctable] Custom/ExplicitSelect: Avoid using all without an explicit .select(...). Autocorrecting to .select(:id).
Driver.all
```
61 changes: 61 additions & 0 deletions lib/rubocop/cop/custom/explicit_select.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Custom
# This cop warns when Active Record queries use `all` or `where`
# without an explicit `.select(...)` clause.
# Autocorrects to `.select(:id)` which needs to be expanded to all fields needed
# by the developer.
class ExplicitSelect < Base
extend AutoCorrector

MSG = 'Avoid using `%<method>s` without an explicit `.select(...)`. Autocorrecting to `.select(:id)`.'

RESTRICT_ON_SEND = %i[all where].freeze

def on_send(node)
return unless inside_active_record_chain?(node)

if node.method?(:all) || node.method?(:select) || node.method?(:where)
unless select_present_in_chain?(node)
add_offense(node, message: format(MSG, method: node.method_name)) do |corrector|
append_select_id(corrector, node)
end
end
end
end

private

def inside_active_record_chain?(node)
# Only apply if the receiver is a constant (e.g., `User.all`)
node.receiver&.const_type?
end

def select_present_in_chain?(node)
visited = Set.new

while node
return true if node.method?(:select) && node.arguments.any?

# Avoid re-visiting the same node (paranoia guard)
break if visited.include?(node)
visited << node

# Walk up the chain safely
node = node.parent if node.parent&.send_type?
break unless node&.send_type?
end

false
end

def append_select_id(corrector, node)
insertion_point = node.source_range.end
corrector.insert_after(insertion_point, '.select(:id)') # Developer must add additional fields beyond :id
end
end
end
end
end