class RuboCop::Cop::Rails::LexicallyScopedActionFilter
This cop checks that methods specified in the filter's `only` or `except` options are defined within the same class or module.
You can technically specify methods of superclass or methods added by mixins on the filter, but these can confuse developers. If you specify methods that are defined in other classes or modules, you should define the filter in that class or module.
If you rely on behaviour defined in the superclass actions, you must remember to invoke `super` in the subclass actions.
@example
# bad class LoginController < ApplicationController before_action :require_login, only: %i[index settings logout] def index end end # good class LoginController < ApplicationController before_action :require_login, only: %i[index settings logout] def index end def settings end def logout end end
@example
# bad module FooMixin extend ActiveSupport::Concern included do before_action proc { authenticate }, only: :foo end end # good module FooMixin extend ActiveSupport::Concern included do before_action proc { authenticate }, only: :foo end def foo # something end end
@example
class ContentController < ApplicationController def update @content.update(content_attributes) end end class ArticlesController < ContentController before_action :load_article, only: [:update] # the cop requires this method, but it relies on behaviour defined # in the superclass, so needs to invoke `super` def update super end private def load_article @content = Article.find(params[:article_id]) end end
Constants
- FILTERS
- MSG
Public Instance Methods
on_send(node)
click to toggle source
# File lib/rubocop/cop/rails/lexically_scoped_action_filter.rb, line 115 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 block = parent.each_child_node(:begin).first return unless block defined_methods = block.each_child_node(:def).map(&:method_name) methods = array_values(methods_node).reject do |method| defined_methods.include?(method) end message = message(methods, parent) add_offense(node, message: message) unless methods.empty? end
Private Instance Methods
array_values(node)
click to toggle source
@param node [RuboCop::AST::Node] @return [Array<Symbol>]
# File lib/rubocop/cop/rails/lexically_scoped_action_filter.rb, line 138 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.map do |v| case v.type when :str v.str_content.to_sym when :sym v.value end end.compact else [] end end
message(methods, parent)
click to toggle source
@param methods [Array<String>] @param parent [RuboCop::AST::Node] @return [String]
# File lib/rubocop/cop/rails/lexically_scoped_action_filter.rb, line 161 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