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

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

Overview

Enforces the use of ‘ActionController::Parameters#expect` as a method for strong parameter handling.

In the following cases, ‘params` is treated as a key that is expected to be passed from the HTTP client, and the cop detects it using the `expect` method.

  • Method calls on ‘params` without comparison methods, methods that are safe to call on `nil` (such as `to_i`, `to_s`, or `is_a?`), key-check methods such as `key?`, collection methods such as `keys`, `merge`, or `slice`, or block-style calls such as `params.each { … }` or `params.map(&:to_s)`

  • Passing ‘params` as an argument to finder methods that raise on missing records

  • Strong parameter methods using ‘require` or `permit`

Other cases are not detected, as they are cases where ‘params` may not be passed from the HTTP client.

Examples:


# bad
params[:key].do_something

# good
params.expect(:key).do_something

# bad
Model.find(params[:id])

# good
Model.find(params.expect(:id))

# bad
Model.find_by!(key: params[:key])

# good
Model.find_by!(key: params.expect(:key))

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

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

Constant Summary collapse

MSG =
'Use `%<prefer>s` instead.'
RESTRICT_ON_SEND =
%i[[] require permit].freeze
IGNORED_METHODS =

Method calls on ‘params` that should not be rewritten with `expect(:key)`. Covers presence/nil checks, nil-safe conversions and type checks, key-check methods, and collection methods that imply `params` is a Hash/Array.

%i[
  ! blank? compact compact! compact_blank compact_blank! deep_merge deep_merge!
  delete delete_if dig each except exclude? extract! fetch has_key? has_value?
  include? inspect instance_of? is_a? keep_if key? keys kind_of? member? merge merge!
  nil? presence present? reverse_merge reverse_merge! slice stringify_keys
  to_a to_f to_h to_hash to_i to_s to_unsafe_h to_unsafe_hash
  transform_keys transform_keys! transform_values transform_values! try try!
  value? values values_at with_defaults with_defaults! without
].freeze
RAISING_FINDER_METHODS =
%i[find find_by! find_sole_by].freeze

Constants included from TargetRailsVersion

TargetRailsVersion::TARGET_GEM_NAME, TargetRailsVersion::USES_REQUIRES_GEM_API

Instance Method Summary collapse

Methods included from TargetRailsVersion

minimum_target_rails_version, support_target_rails_version?

Instance Method Details

#on_send(node) ⇒ Object Also known as: on_csend

rubocop:disable Metrics/AbcSize, Metrics/MethodLength



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/rubocop/cop/rails/strong_parameters_expect.rb', line 113

def on_send(node)
  return if part_of_ignored_node?(node)

  if (params_key = params_bracket_access(node))
    register_bracket_access_offense(node, params_key)
    return
  end

  if (permit_method, require_method = params_require_permit(node))
    range = offense_range(require_method, node)
    prefer = expect_method(require_method, permit_method)
    replace_argument = true
  elsif (require_method, permit_method = params_permit_require(node))
    range = offense_range(permit_method, node)
    prefer = "expect(#{permit_method.arguments.map(&:source).join(', ')})"
    replace_argument = false
  else
    return
  end

  add_offense(range, message: format(MSG, prefer: prefer)) do |corrector|
    corrector.remove(require_method.receiver.source_range.end.join(require_method.source_range.end))
    corrector.replace(permit_method.loc.selector, 'expect')
    if replace_argument
      corrector.insert_before(permit_method.first_argument, "#{require_key(require_method)}[")
      corrector.insert_after(permit_method.last_argument, ']')
    end
  end

  ignore_node(node)
end