Reputation: 11494
I want to have a list of URLs my Rails app supports, but I do not want to provide any arguments ahead of time.
For example, I want to list the path for user_registration_path
as /%{locale}/users/sign_up
.
I can get a list of named routes like so (testing in Rails console):
Rails.application.routes.named_routes.helper_names
Example output:
["rails_info_properties_path", "rails_info_routes_path", "rails_info_path", "rails_mailers_path", "rails_service_blob_path", "rails_blob_path", "rails_blob_representation_path", "rails_representation_path", "rails_disk_service_path"...]
Is there any way to achieve this in Rails?
Upvotes: 0
Views: 3289
Reputation: 102174
You can do this quite simply by looking at how rails dumps the routes with the rails routes
command.
# frozen_string_literal: true
require "rails/command"
module Rails
module Command
class RoutesCommand < Base # :nodoc:
class_option :controller, aliases: "-c", desc: "Filter by a specific controller, e.g. PostsController or Admin::PostsController."
class_option :grep, aliases: "-g", desc: "Grep routes by a specific pattern."
class_option :expanded, type: :boolean, aliases: "-E", desc: "Print routes expanded vertically with parts explained."
def perform(*)
require_application_and_environment!
require "action_dispatch/routing/inspector"
say inspector.format(formatter, routes_filter)
end
private
def inspector
ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes)
end
def formatter
if options.key?("expanded")
ActionDispatch::Routing::ConsoleFormatter::Expanded.new
else
ActionDispatch::Routing::ConsoleFormatter::Sheet.new
end
end
def routes_filter
options.symbolize_keys.slice(:controller, :grep)
end
end
end
end
The key here is:
inspector.format(formatter, routes_filter)
Where formatter is really just a class that responds to section
, header
and result
:
# formats routes as a simple array of hashes
class HashFormatter
def initialize
@buffer = []
end
# called for the main routes and also for each
# mounted engine
def section(routes)
routes.each do |r|
@buffer << r.slice(:name, :verb, :path)
end
end
# this method does not need to do anything since the "headers" are
# part of the hashes
def header(routes)
end
def result
@buffer
end
end
We can then invoke our formatter with:
inspector = ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes)
inspector.format(HashFormatter.new)
And get an array of hashes:
[{:name=>"", :verb=>"GET", :path=>"/pizzas/:foo(.:format)"}, {:name=>"", :verb=>"GET", :path=>"/pizzas/:foo/:bar(.:format)"}, {:name=>"", :verb=>"GET", :path=>"/pizzas/:foo/:bar/:baz(.:format)"}, {:name=>"foo", :verb=>"DELETE", :path=>"/foo(.:format)"}, {:name=>"root", :verb=>"GET", :path=>"/"}, #...]
The advantage here is that you're piggybacking on existing code that gathers the routes for any mounted engines and rejects internal routes.
Upvotes: 3
Reputation: 2086
you can try to work on this command:
Rails.application.routes.routes
.map { |r| { path: r.path.spec.to_s } }
it will give you this output:
{:path=>"/admin/users/:id/edit(.:format)"},
{:path=>"/admin/users/:id(.:format)"},
{:path=>"/admin/users/:id(.:format)"},
{:path=>"/admin/users/:id(.:format)"},
Or as an array (you can improve it, it's just a quick example):
Rails.application.routes.routes
.flat_map { |r| r.path.spec.to_s }
.uniq
.map { |path| path.gsub('(.:format)', '') }
[
"/admin/users",
"/admin/users/new",
"/admin/users/:id/edit",
"/admin/users/:id"
]
Upvotes: 7