Class: RuboCop::Cop::DevDoc::Route::ResourcesRequireOnly

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/dev_doc/route/resources_require_only.rb

Overview

Always use only: for resources / resource in routes.rb.

Rationale

When defining routes in routes.rb, it is important to explicitly specify the desired actions using the only option. This helps prevent accidentally exposing actions that should not be accessible — leaving the default opens the full RESTful set, which often exposes routes the application has no controller action for, or routes that probably should be locked down.

only: is preferred over except: because it is explicit about what is exposed. except: exposes everything not in the list, which is easier to misread when the action set changes.

Set RequireOnly: false to accept both only: and except:.

✔️
resources :job_applications, only: [:index, :new, :create]

Examples:

EnforcedStyle: RequireOnly (default)

# bad
resources :users
resources :users, except: [:destroy]

# good
resources :users, only: %i[index show]

EnforcedStyle: RequireOnly: false

# bad
resources :users

# good
resources :users, only: %i[index show]
resources :users, except: [:destroy]

Constant Summary collapse

MSG =
'Specify `only:` or `except:` for `%<method>s :%<name>s` to avoid exposing unintended actions.'.freeze
MSG_REQUIRE_ONLY =
'Specify `only:` for `%<method>s :%<name>s` ' \
'(`except:` is allowed only with `RequireOnly: false`).'.freeze
RESTRICT_ON_SEND =
%i[resources resource].freeze

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/rubocop/cop/dev_doc/route/resources_require_only.rb', line 45

def on_send(node)
  has_only = key_present?(node, :only)
  has_except = key_present?(node, :except)

  return if has_only
  return if has_except && !require_only?

  name = node.first_argument&.value || '?'
  msg = has_except && require_only? ? MSG_REQUIRE_ONLY : MSG
  add_offense(node.loc.selector, message: format(msg, method: node.method_name, name: name))
end