Class: RuboCop::Cop::DevDoc::Rails::StrongParametersExpect

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Defined in:
lib/rubocop/cop/dev_doc/rails/strong_parameters_expect.rb

Overview

Flag params.require(:foo).permit(...) and the reverse form params.permit(foo: ...).require(:foo) — use params.expect(foo: [...]) instead.

Rationale

The upstream Rails/StrongParametersExpect autocorrects two distinct patterns: the hash-form rewrite (require.permitexpect) and the scalar form (params[:id] inside find-method chains). The scalar form fires false positives on optional query params (e.g. params[:status]&.to_sym || :draft) and forces scattered per-line disables — the typical workaround is to disable the upstream cop entirely, losing the hash-form benefit too.

This cop targets only the hash-form rewrite, so projects can keep Rails/StrongParametersExpect: Enabled: false and still enforce the safe params.expect pattern.

params.expect raises ActionController::ParameterMissing for scalar values where permit would silently return nil, and it makes the permitted-attribute shape explicit in one call.

Patterns detected

 require  permit chain
params.require(:user).permit(:name, :email)

 permit  require chain (less common)
params.permit(user: %i[name email]).require(:user)

✔️
params.expect(user: [:name, :email])

Not flagged

Scalar params[:foo] in any context — leave that to per-project decision or the upstream cop.

Autocorrect is UNSAFE (SafeAutoCorrect: false)

expect is not a drop-in for require+permit; both deltas below were verified against a production suite (81 test failures before manual fix-ups):

  1. Empty-slice 400: expect raises ParameterMissing when the key is present but every value filters out — permit returned an empty slice and proceeded. Bites "slice-style" param methods that probe for whichever keys arrived (e.g. a publishing_params called unconditionally in update). Keep those tolerant with params.fetch(:key, {}).permit(...) + an inline reason.
  2. Silent collection loss: expect filters with explicit_arrays, so collection-valued nested attributes (numeric-keyed fields_for / dynamic-group hashes, {"0"=>{...}}) require the double-array [[...]] declaration. The flat [...] this autocorrect emits SILENTLY filters such collections to empty — no error, no data. After correcting, audit every *_attributes key: has_many nests need [[...]], has_one nests stay flat.

The corrector also deliberately skips permit calls whose arguments are computed (e.g. permit([...static...] + extra)): copying the expression into expect(key: [<expr>]) would produce a one-element outer array — which IS expect's array-of-hashes syntax, silently changing semantics. Those sites are flagged without a correction.

Examples:

# bad
params.require(:user).permit(:name, :email)

# bad
params.require(:user).permit(:name, profile_attributes: [:bio])

# bad
params.permit(user: %i[name email]).require(:user)

# good
params.expect(user: [:name, :email])

# good
params.expect(user: [:name, { profile_attributes: [:bio] }])

Constant Summary collapse

MSG_REQUIRE_PERMIT =
'Use `params.expect(%<key>s: [...])` instead of ' \
'`params.require(:%<key>s).permit(...)`.'.freeze
MSG_PERMIT_REQUIRE =
'Use `params.expect(%<key>s: ...)` instead of ' \
'`params.permit(%<key>s: ...).require(:%<key>s)`.'.freeze
RESTRICT_ON_SEND =
%i[permit require].freeze

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ Object



91
92
93
94
# File 'lib/rubocop/cop/dev_doc/rails/strong_parameters_expect.rb', line 91

def on_send(node)
  check_require_permit(node) if node.method_name == :permit
  check_permit_require(node) if node.method_name == :require
end