class RuboCop::Cop::Rails::LexicallyScopedActionFilter

end
end
@content = Article.find(params)
def load_article
private
end
super
def update
# in the superclass, so needs to invoke ‘super`
# the cop requires this method, but it relies on behavior defined
before_action :load_article, only: [:update]
class ArticlesController < ContentController
end
end
@content.update(content_attributes)
def update
class ContentController < ApplicationController
@example
end
end
# something
def foo
end
before_action proc { authenticate }, only: :foo
included do
extend ActiveSupport::Concern
module FooMixin
# good
end
end
before_action proc { authenticate }, only: :foo
included do
extend ActiveSupport::Concern
module FooMixin
# bad
@example
end
end
def logout
end
def settings
end
def index
before_action :require_login, only: %i[index settings logout]
class LoginController < ApplicationController
# good
end
end
def index
before_action :require_login, only: %i[index settings logout]
class LoginController < ApplicationController
# bad
@example
remember to invoke `super` in the subclass actions.
If you rely on behavior defined in the superclass actions, you must
define the filter in that class or module.
methods that are defined in other classes or modules, you should
mixins on the filter, but these can confuse developers. If you specify
You can technically specify methods of superclass or methods added by
@safety
`except` options are defined within the same class or module.
Checks that methods specified in the filter’s ‘only` or

def alias_methods(node)

def alias_methods(node)
  result = {}
  node.each_child_node(:send, :alias) do |child_node|
    case child_node.type
    when :send
      if child_node.method?(:alias_method)
        result[child_node.last_argument.value] = child_node.first_argument.value
      end
    when :alias
      result[child_node.old_identifier.value] = child_node.new_identifier.value
    end
  end
  result
end

def aliased_action_methods(node, defined_methods)

def aliased_action_methods(node, defined_methods)
  alias_methods = alias_methods(node)
  defined_methods.each_with_object([]) do |defined_method, aliased_method|
    if (new_method_name = alias_methods[defined_method])
      aliased_method << new_method_name
    end
  end
end

def array_values(node) # rubocop:disable Metrics/MethodLength

Returns:
  • (Array) -

Parameters:
  • node (RuboCop::AST::Node) --
def array_values(node) # rubocop:disable Metrics/MethodLength
  case node.type
  when :str
    [node.str_content.to_sym]
  when :sym
    [node.value]
  when :array
    node.values.filter_map do |v|
      case v.type
      when :str
        v.str_content.to_sym
      when :sym
        v.value
      end
    end
  else
    []
  end
end

def defined_action_methods(block)

def defined_action_methods(block)
  return [] unless block
  defined_methods = block.each_child_node(:def).map(&:method_name)
  defined_methods + delegated_action_methods(block) + aliased_action_methods(block, defined_methods)
end

def delegated_action_methods(node)

def delegated_action_methods(node)
  node.each_child_node(:send).flat_map do |child_node|
    delegated_methods(child_node) || []
  end
end

def message(methods, parent)

Returns:
  • (String) -

Parameters:
  • parent (RuboCop::AST::Node) --
  • methods (Array) --
def message(methods, parent)
  if methods.size == 1
    format(MSG, action: "`#{methods[0]}` is", type: parent.type)
  else
    format(MSG, action: "`#{methods.join('`, `')}` are", type: parent.type)
  end
end

def on_send(node)

def on_send(node)
  methods_node = only_or_except_filter_methods(node)
  return unless methods_node
  parent = node.each_ancestor(:class, :module).first
  return unless parent
  # NOTE: a `:begin` node may not exist if the class/module consists of a single statement
  block = parent.each_child_node(:begin).first
  defined_action_methods = defined_action_methods(block)
  unmatched_methods = array_values(methods_node) - defined_action_methods
  return if unmatched_methods.empty?
  message = message(unmatched_methods, parent)
  add_offense(node, message: message)
end