class RailsBestPractices::Reviews::RestrictAutoGeneratedRoutesReview
Review
a route file to make sure all auto-generated routes have corresponding actions in controller.
See the best practice details here rails-bestpractices.com/posts/2011/08/19/restrict-auto-generated-routes/
Implementation:
Review
process:
check all resources and resource method calls, compare the generated routes and corresponding actions in controller, if there is a route generated, but there is not action in that controller, then you should restrict your routes.
Public Class Methods
new(options = {})
click to toggle source
Calls superclass method
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 33 def initialize(options = {}) super(options) @namespaces = [] @resource_controllers = [] end
Public Instance Methods
check_method_add_block?(node)
click to toggle source
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 92 def check_method_add_block?(node) node[1].sexp_type == :command || (node[1].sexp_type == :command_call && node.receiver.to_s != 'map') end
resource_methods()
click to toggle source
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 21 def resource_methods if Prepares.configs['config.api_only'] %w[show create update destroy] else %w[show new create edit update destroy] end end
resources_methods()
click to toggle source
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 29 def resources_methods resource_methods + ['index'] end
Private Instance Methods
_check(node, methods)
click to toggle source
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 134 def _check(node, methods) controller_name = controller_name(node) return unless Prepares.controllers.include? controller_name _methods = _methods(node, methods) unless _methods.all? { |meth| Prepares.controller_methods.has_method?(controller_name, meth) } prepared_method_names = Prepares.controller_methods.get_methods(controller_name).map(&:method_name) only_methods = (_methods & prepared_method_names).map { |meth| ":#{meth}" } routes_message = if only_methods.size > 3 "except: [#{(methods.map { |meth| ':' + meth } - only_methods).join(', ')}]" else "only: [#{only_methods.join(', ')}]" end add_error "restrict auto-generated routes #{friendly_route_name(node)} (#{routes_message})" end end
_methods(node, methods)
click to toggle source
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 152 def _methods(node, methods) if option_with_hash(node) option_node = node.arguments.all[1] if hash_key_exist?(option_node, 'only') option_node.hash_value('only').to_s == 'none' ? [] : Array(option_node.hash_value('only').to_object) elsif hash_key_exist?(option_node, 'except') if option_node.hash_value('except').to_s == 'all' [] else (methods - Array(option_node.hash_value('except').to_object)) end else methods end else methods end end
check_resource(node)
click to toggle source
check resource call, if the routes generated by resources does not exist in the controller.
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 104 def check_resource(node) _check(node, resource_methods) end
check_resources(node)
click to toggle source
check resources call, if the routes generated by resources does not exist in the controller.
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 99 def check_resources(node) _check(node, resources_methods) end
controller_name(node)
click to toggle source
get the controller name.
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 109 def controller_name(node) if option_with_hash(node) option_node = node.arguments.all[1] name = if hash_key_exist?(option_node, 'controller') option_node.hash_value('controller').to_s else node.arguments.all.first.to_s.gsub('::', '').tableize end else name = node.arguments.all.first.to_s.gsub('::', '').tableize end namespaced_class_name(name) end
friendly_route_name(node)
click to toggle source
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 186 def friendly_route_name(node) if @resource_controllers.last == node.arguments.to_s [@namespaces.join('/'), @resource_controllers.join('/')].delete_if(&:blank?).join('/') else [@namespaces.join('/'), @resource_controllers.join('/'), node.arguments.to_s].delete_if(&:blank?).join('/') end end
hash_key_exist?(node, key)
click to toggle source
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 182 def hash_key_exist?(node, key) node.hash_keys&.include?(key) end
module_option(node)
click to toggle source
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 171 def module_option(node) option_node = node.arguments[1].last if option_node && option_node.sexp_type == :bare_assoc_hash && hash_key_exist?(option_node, 'module') option_node.hash_value('module').to_s end end
namespaced_class_name(name)
click to toggle source
get the class name with namespace.
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 125 def namespaced_class_name(name) class_name = "#{name.split('/').map(&:camelize).join('::')}Controller" if @namespaces.empty? class_name else @namespaces.map { |namespace| "#{namespace.camelize}::" }.join('') + class_name end end
option_with_hash(node)
click to toggle source
# File lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb, line 178 def option_with_hash(node) node.arguments.all.size > 1 && node.arguments.all[1].sexp_type == :bare_assoc_hash end