Rails 获取路由列表作为带参数的路径

Rails get list of routes as paths with parameters

我想要一份我的 Rails 应用支持的 URL 列表,但我不想提前提供任何参数。

例如,我想将 user_registration_path 的路径列为 /%{locale}/users/sign_up

我可以像这样获得命名路由列表(在 Rails 控制台中测试):

Rails.application.routes.named_routes.helper_names

示例输出:

["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"...]

在Rails中有什么方法可以做到这一点吗?

您可以尝试使用此命令:

Rails.application.routes.routes
  .map { |r| { path: r.path.spec.to_s } }

它会给你这个输出:

{:path=>"/admin/users/:id/edit(.:format)"},
{:path=>"/admin/users/:id(.:format)"},
{:path=>"/admin/users/:id(.:format)"},
{:path=>"/admin/users/:id(.:format)"},

或者作为一个数组(你可以改进它,这只是一个简单的例子):

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"
]

您可以通过使用 rails routes 命令查看 rails dumps the routes 的方式来非常简单地完成此操作。

# 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

这里的关键是:

inspector.format(formatter, routes_filter)

格式化程序实际上只是一个响应 sectionheaderresult:

的 class
# 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

然后我们可以调用我们的格式化程序:

inspector = ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes)
inspector.format(HashFormatter.new)

并得到一个哈希数组:

[{: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=>"/"}, #...]

这里的优点是您可以利用现有代码收集任何已安装引擎的路由并拒绝内部路由。