【问题标题】:Trying to understand Journey::Path::Pattern#spec (internal of Rails routing)试图理解 Journey::Path::Pattern#spec(Rails 路由内部)
【发布时间】:2019-08-24 12:27:23
【问题描述】:

上下文:我正在解决一个问题,我需要一个外部审计程序才能理解和“应用”Rails 路由。编写此外部程序的一种选择可能是解析rake routes 的输出,但这会不必要地重复解析这些路由并将它们转换为结构良好的Journey::Route 对象的代码。

因此,我的计划是将Rails.application.routes输出为外部程序可以理解的通用格式(YAML或JSON),并可以根据此数据构建路由器。

问题:鉴于这种情况,我试图了解Journey::Path::Paternet#spec 属性的结构,它出现在Journey::Route 对象内,并且恰好是所有操作的中心。

例如,以下路线 - /posts/:id - 被转换为以下“规范” -

 #<Journey::Nodes::Cat:0x00007ff193327ee0
 @left=
  #<Journey::Nodes::Cat:0x00007ff193308630
   @left=
    #<Journey::Nodes::Cat:0x00007ff1933087e8
     @left=
      #<Journey::Nodes::Cat:0x00007ff193308bf8
       @left=#<Journey::Nodes::Slash:0x00007ff193308d38 @left="/", @memo=nil>,
       @memo=nil,
       @right=#<Journey::Nodes::Literal:0x00007ff193308c48 @left="posts", @memo=nil>>,
     @memo=nil,
     @right=#<Journey::Nodes::Slash:0x00007ff193308a40 @left="/", @memo=nil>>,
   @memo=nil,
   @right=#<Journey::Nodes::Symbol:0x00007ff1933086d0 @left=":id", @memo=nil, @regexp=/[^\.\/\?]+/>>,
 @memo=nil,
 @right=
  #<Journey::Nodes::Group:0x00007ff193309c10
   @left=
    #<Journey::Nodes::Cat:0x00007ff193308220
     @left=#<Journey::Nodes::Dot:0x00007ff1933084f0 @left=".", @memo=nil>,
     @memo=nil,
     @right=#<Journey::Nodes::Symbol:0x00007ff193308338 @left=":format", @memo=nil, @regexp=/[^\.\/\?]+/>>,
   @memo=nil>>
  • Journey::Nodes::Cat 对象中的左/右属性是什么?是什么决定了哪个令牌是“左”,哪个令牌是“右”
  • 这看起来有点像二叉树,但为什么第一个标记(即第一个/)是“最内层”(或叶节点)?不应该是“最外层”(或根节点)吗?
  • 在执行路线匹配时,在此数据结构中遍历此数据结构的有效方法是什么?

【问题讨论】:

    标签: ruby-on-rails routes internals journey


    【解决方案1】:

    Journey 基于匹配路线的有限状态机,内置可视化工具(需要 graphviz):

    File.open('routes.html', 'wt'){|f| f.write Rails.application.routes.router.visualizer }
    

    Journey::Nodes::Cat 只是你可以遇到的一种节点类型,它是匹配路径expressions 规则的二进制节点grammar, see parser.y,左边是第一个expressionright 是所有其他的,这会产生循环消耗所有表达式。

    关于外部路由分析的其他想法:在一般情况下,路由不能转储到静态文件中,因为它们可以包含:

    • 具有非纯函数的动态约束(例如 - get :r, constraints: -&gt;{rand(2)&gt;0},想法是结果可能取决于请求、时间或状态等之外的东西)当这些存在时 - 甚至 rails 路由器本身也可以在第二次运行相同的请求时产生不同的结果。

    • 安装的机架应用程序 - 可以有硬编码或非 Rails 路由器

    • rails 引擎 - 具有 rails 路由器,比通用机架应用程序更容易,但在挂载点和合并到主应用程序范围方面存在技巧

    但对于简单的情况,您可以利用用于 rake routes 的 rails 的 ActionDispatch::Routing::RoutesInspector 并获得比仅解析后者输出更好的结构化路由信息。

    在 gem routes_coverage 我是这样做的:

    class Inspector < ActionDispatch::Routing::RoutesInspector
      def collect_all_routes
        res = collect_routes(@routes)
        @engines.each do |engine_name, engine_routes|
          res += engine_routes.map{|er|
            er.merge({ engine_name: engine_name })
          }
        end
        res
      end
    
      def collect_routes(routes)
        routes.collect do |route|
          ActionDispatch::Routing::RouteWrapper.new(route)
        end.reject do |route|
          route.internal?
        end.collect do |route|
          collect_engine_routes(route)
    
          { name:   route.name,
            verb:   route.verb,
            path:   route.path,
            reqs:   route.reqs,
            original: route,
          }
        end
      end
    
    res = Inspector.new(Rails.application.routes.routes.routes).collect_all_routes
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 2011-11-23
      相关资源
      最近更新 更多