Identify unused Routes in Ruby on Rails

Reading time: 4 minutes

Custom Rake Task: Identify unused routes in Ruby on Rails

Rails routes map URLs of a Ruby on Rails application to controller actions. As a project grows, many new routes get added and older ones might become obsolete. Cleanup of unused routes is a good practice to keep the codebase clean and maintainable. This article shows how you can identify unused routes in Ruby on Rails before 7.1 and after 7.1 with built-in tooling.

Before Ruby on Rails 7.1

Before Ruby on Rails 7.1, there is no built-in tool to identify unused routes in a project. However, some gems that can help you with this task like traceroute or a custom rake task like this:

# lib/tasks/routes_unused.rake
namespace :routes do
  desc "List unused routes"
  task unused: :environment do
    unused_routes = {}

    Rails.application.routes.routes.each do |route|
      controller_name = route.requirements[:controller].to_s.camelize
      controller_class = "#{controller_name}Controller"
      action = route.requirements[:action].to_s

      if Object.const_defined?(controller_class) &&
        !controller_class.constantize.new.respond_to?(action)
        controller = controller_class.constantize
        views_path = Rails.root.join("app", "views",
          controller.controller_path, "#{action}.*")
        unless Dir.glob(views_path).any?
          unused_routes[controller_class] = [] if unused_routes[controller].nil?
          unused_routes[controller_class] << action
        end
      end
    end

    unused_routes.each do |route, actions|
      actions.each do |action|
        p "#{route}##{action}"
      end
    end

    # return value 1 if there are unused routes to use it in CI/CD pipeline
    exit 1 if unused_routes.present?
  end
end

You can run this rake task with bundle exec rake routes:unused or bin/rails routes:unused to get a list of unused routes in your project.

The output will look like this:

$ bin/rails routes:unused
"UsersController#destroy"

This rake task has some limitations. It only checks if the controller and action are both defined. If no action is determined, it will check for an existing view file in the views folder with action as a name.

After Ruby on Rails 7.1

With Ruby on Rails 7.1, a new command-line tool called bin/rails routes --unused was added by PR rails#45701. It does the same as the custom rake task above. You can run it with bin/rails routes --unused to get a list of unused routes in your project:

$ bin/rails routes --unused
Found 1 unused route:

Prefix Verb   URI Pattern             Controller#Action
       DELETE /users/:id(.:format)    users#destroy

This command will output a list of unused routes in your project. It will show the HTTP verb, the URI pattern, and the controller action of the unused route.

It is a great addition to the Ruby on Rails tooling and makes it easier to identify unused routes in a Rails project. This is especially useful for large projects with many routes or legacy projects being refactored.

Limitations

As for both the custom rake task and the built-in command, there are some limitations you have to consider:

Run in CI/CD Pipeline

You can use both commands as part of your CI/CD pipeline to ensure that no new unused routes are added to the project helping developers. This can be also added to a bin/check script, which runs all checks before pushing to the repository.

The output in a Ruby on Rails 7.1 project or later will be:

$ bin/rails routes --unused
Found 1 unused route:

Prefix Verb   URI Pattern             Controller#Action
       DELETE /users/:id(.:format)    users#destroy

$ echo $?
1

For a Ruby on Rails project before 7.1 using my rake task, the output will be:

$ bin/rails routes:unused
"UsersController#destroy"

$ echo $?
1

Conclusion

Identifying unused routes in a Ruby on Rails project is a good practice to keep the codebase clean and maintainable. Before Ruby on Rails 7.1, you could use a custom rake task or a gem like traceroute to identify unused routes. With Ruby on Rails 7.1, you can use the built-in command bin/rails routes --unused to get a list of unused routes in your project. This is especially useful for large projects with many routes where it is hard to keep track of all routes manually.


Newsletter


See Also


Tags