class RailsRoutesAnalyzer::ActionAnalysis
Constants
- PREAMBLE_WARNING
Attributes
all_action_methods[R]
options[R]
unused_controllers[R]
Public Class Methods
new(route_analysis: RailsRoutesAnalyzer::RouteAnalysis.new, report_routed: false, report_duplicates: false, report_gems: false, report_modules: false, full_path: false, metadata: false)
click to toggle source
Options:
report_duplicates - report actions which the parent controller also has report_gems - report actions which are implemented by a gem report_modules - report actions inherited from modules report_routed - report all actions including those with a route full_path - skips shortening file paths metadata - include discovered metadata about actions
# File lib/rails_routes_analyzer/action_analysis.rb, line 77 def initialize(route_analysis: RailsRoutesAnalyzer::RouteAnalysis.new, report_routed: false, report_duplicates: false, report_gems: false, report_modules: false, full_path: false, metadata: false) @options = { report_routed: report_routed, report_duplicates: report_duplicates, report_gems: report_gems, report_modules: report_modules, full_path: full_path, metadata: metadata, } @all_action_methods = analyze_action_methods(route_analysis: route_analysis) @by_controller = @all_action_methods.group_by(&:controller_class) @unused_controllers = find_unused_controllers end
Public Instance Methods
print_actions_report()
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 105 def print_actions_report @controller_reporting_cache = {} report_actions_recursive end
print_report()
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 100 def print_report print_missing_routes_report_preamble unless options[:report_routed] print_actions_report end
Protected Instance Methods
actions_for(controller)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 119 def actions_for(controller) @by_controller[controller] || [] end
actions_to_report(controller)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 123 def actions_to_report(controller) actions_for(controller).select do |action| action.needs_reporting?(**options) end.sort_by(&:action_name) end
analyze_action_methods(route_analysis:)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 189 def analyze_action_methods(route_analysis:) implemented_routes = Set.new(route_analysis.implemented_routes) [].tap do |result| ActionController::Base.descendants.each do |controller| next if default_controller?(controller) action_methods = controller.action_methods.to_a.map(&:to_sym) if (parent_controller = controller.superclass) == ActionController::Base parent_controller = nil parent_actions = [] else parent_actions = parent_controller.action_methods.to_a.map(&:to_sym) end action_methods.each do |action_name| controller_name = controller.name source_location = get_source_location(controller, action_name) owner = controller.instance_method(action_name).owner # A very strong likelyhood is that if the method is not defined by a module # it comes directly from any ActionController::Base subclass. # # This knowledge helps us ignore methods which might come for example from # someone (possibly unwisely) including a helper directly into a controller. from_module = owner.class == Module is_inherited = parent_actions.include?(action_name) \ && get_source_location(parent_controller, action_name) == source_location route_missing = !implemented_routes.include?([controller_name, action_name]) sanitized_location = RailsRoutesAnalyzer.sanitize_source_location(source_location, options.slice(:full_path)) result << ActionMethod.new( controller_name: controller_name, action_name: action_name, is_inherited: is_inherited, route_missing: route_missing, source_location: sanitized_location, from_gem: GemManager.identify_gem(source_location), owner: owner, from_module: from_module, ) end end end end
controller_has_no_routes?(controller)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 184 def controller_has_no_routes?(controller) no_direct_routes_to?(controller) \ && controller.subclasses.all? { |c| controller_has_no_routes?(c) } end
controller_likely_from_gem?(controller)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 154 def controller_likely_from_gem?(controller) actions_for(controller).all? { |action| action.from_gem? || action.from_module? || action.inherited? } end
controller_needs_reporting?(controller)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 158 def controller_needs_reporting?(controller) if @controller_reporting_cache.key?(controller) return @controller_reporting_cache[controller] end @controller_reporting_cache[controller] = \ actions_to_report(controller).any? \ || controller.subclasses.any? { |subclass| controller_needs_reporting?(subclass) } end
default_controller?(controller)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 176 def default_controller?(controller) defined?(::Rails::ApplicationController) && controller <= ::Rails::ApplicationController end
find_unused_controllers()
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 168 def find_unused_controllers ActionController::Base.descendants.select do |controller| controller_has_no_routes?(controller) \ && !default_controller?(controller) \ && (options[:report_gems] || !controller_likely_from_gem?(controller)) end end
get_source_location(controller_class_or_name, action_name)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 240 def get_source_location(controller_class_or_name, action_name) controller = controller_class_or_name controller = controller.constantize if controller.is_a?(String) controller.instance_method(action_name).source_location.join(':') end
no_direct_routes_to?(controller)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 180 def no_direct_routes_to?(controller) actions_for(controller).all?(&:route_missing?) end
print_missing_routes_report_preamble()
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 258 def print_missing_routes_report_preamble unless unused_actions_present? puts "There are no actions without a route" return end if unused_controllers.present? puts "Controllers with no routes pointing to them:" unused_controllers.sort_by(&:name).each do |controller| puts " #{controller.name}" end puts "" end puts PREAMBLE_WARNING end
report_actions_recursive(controllers = ActionController::Base.subclasses, level = 0)
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 129 def report_actions_recursive(controllers = ActionController::Base.subclasses, level = 0) controllers.each do |controller| next unless controller_needs_reporting?(controller) puts "#{' ' * level}#{controller.name}" if (actions = actions_to_report(controller)).any? action_level = level + 1 if controller.subclasses.any? { |subclass| controller_needs_reporting?(subclass) } puts "#{' ' * action_level}Actions:" action_level += 1 end max_action_length = [MAX_ACTION_LENGTH, actions.map { |a| a.action_name.size }.max].min actions.each do |action| puts "#{' ' * action_level}#{action.pretty(max_action_length: max_action_length, **options)}" end end report_actions_recursive(controller.subclasses.sort_by(&:name), level + 1) end end
unused_actions_present?()
click to toggle source
# File lib/rails_routes_analyzer/action_analysis.rb, line 113 def unused_actions_present? @all_action_methods.any? do |action| action.needs_reporting?(**options) end end