class RuboCop::Cop::Rails::StrongParametersExpect


params.expect(user: [:name, :age])
# good
params.permit(user: [:name, :age]).require(:user)
params.require(:user).permit(:name, :age)
# bad
@example
strong parameter conventions.
incompatibility introduced for valid reasons by the ‘expect` method, which aligns better with
from 500 to 400 when handling invalid parameters. This change, however, reflects an intentional
This cop’s autocorrection is considered unsafe because there are cases where the HTTP status may change
@safety
Enforces the use of ‘ActionController::Parameters#expect` as a method for strong parameter handling.

def expect_method(require_method, permit_method)

def expect_method(require_method, permit_method)
  require_key = require_key(require_method)
  permit_args = permit_method.arguments.map(&:source).join(', ')
  arguments = "#{require_key}[#{permit_args}]"
  "expect(#{arguments})"
end

def offense_range(method_node, node)

def offense_range(method_node, node)
  method_node.loc.selector.join(node.source_range.end)
end

def on_send(node)

rubocop:disable Metrics/AbcSize, Metrics/MethodLength
def on_send(node)
  return if part_of_ignored_node?(node)
  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

def require_key(require_method)

def require_key(require_method)
  if (first_argument = require_method.first_argument).respond_to?(:value)
    require_arg = first_argument.value
    separator = ': '
  else
    require_arg = first_argument.source
    separator = ' => '
  end
  "#{require_arg}#{separator}"
end