【问题标题】:Sinatra routing evaluation, relating to dynamic routesSinatra 路由评估,与动态路由相关
【发布时间】:2011-10-28 19:19:21
【问题描述】:

希望这将是一个简单的答案,我对 Ruby 和 Sinatra 都是新手。

我正在考虑使用模块化方法编写一个 sinatra 应用程序,但是我希望能够以插件方式添加新路由。

目前我有我的 SinatraApp 类,它继承自 Sinatra::Base,现在我有一个名为 load_plugins 的方法,它通过插件文件夹并包括所有 routing-definition.rb 文件,这些文件是包含更多路由的模块。

因此,在这个问题的背景下,我想知道 Sinatra 如何管理其路由。是在第一次初始化时加载 SinatraApp,然后将其保存在机架进程(或您在其中运行它的任何内容)中的内存中,还是 SinatraApp 重新评估每个请求?

以这个场景为例,用户A加载一个返回html页面的路由,用户A点击一个链接并返回404,因为插件不存在,AdminA然后将一个新插件添加到插件文件夹中,用户A然后刷新他们的页面,他们得到一个 html 页面而不是 404,因为插件已经添加了路由。

会发生上述情况,还是我需要重新启动 Sinatra 服务器以获取新的插件文件?

我的一部分人希望它会在每个请求中更新加载的插件......但是我的一部分人知道,如果每个请求都需要扫描目录以查找插件,这会影响性能。

== 编辑 ==

在下面添加了我的意思的示例。我不确定它是否应该像模块一样构造或像下面那样保持内联,如果包含字面代码转储到当前范围,那么 get "" 会知道它应该在 SinatraMain 应用程序的范围内调用 get,无论哪种方式告诉你我在追求什么。

require 'sinatra'

class SinatraMain < Sinatra::Base

    def load_plugins
        Dir["/plugins/**/routing-plugin.rb"].each  do |plugin_file| 
            include plugin_file
        end
    end

  get "/test" do
    return "This is a test route"
  end

get "/plugins/*" do
   load_plugins
   return "Plugins refreshed"
end
end

SinatraMain.run!

# Imagine this was within /plugins/SayHelloPlugin/routing-plugin.rb
get "/say-hello"
    return "Saying hello"
end

所以想法是每当这些 plugin 文件添加到插件文件夹时,它应该将路由添加到应用程序,当它们被删除时,将它们从路由中取出(尽管后者点现在不那么重要了)。

【问题讨论】:

    标签: ruby plugins routing sinatra


    【解决方案1】:

    根据我对源代码 (https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb) 的阅读,Sinatra 将路由作为类变量存储在 Sinatra::Base 类中,因此路由虽然 Sinatra/Rack 会为每个请求创建一个新的应用实例,但不会针对每个请求重新评估。

    您当然可以在运行时添加额外的路由,而无需重新加载所有路由。我不知道您是如何加载插件的,但应该可以在不重新启动 Sinatra 的情况下执行您想要的操作,这是一个添加新路由的粗略演示/实验:

    require 'rubygems'
    require 'sinatra/base'
    
    class App < Sinatra::Base
      get '/' do
        "hello [self.object_id: #{self.object_id}, App.routes.object_id: #{App.routes.object_id}]"
      end
    
      get '/add_route' do
        App.get '/new_route' do
          "from new route [self.object_id: #{self.object_id}, App.routes.object_id: #{App.routes.object_id}]"
        end
        "new route added [self.object_id: #{self.object_id}, App.routes.object_id: #{App.routes.object_id}]"
      end
    
      run! if /app.rb$/ =~ $0
    end
    

    如果您运行它,您将看到应用程序在每个请求上都获得一个新的 object_id,但 App.routes 哈希始终是同一个对象。

    【讨论】:

    • 所以我猜你需要某种非阻塞文件观察器来触发 load_plugins 方法或类似的东西。这不是我自己做过的事情,我知道有许多 Ruby 文件观察器可用,例如EventMachine 有一个我猜你可以集成到你的应用程序中。在您的插件文件中,您可以扩展您的 SinatraMain 类并使用 Kernel#load 或 Kernel#require 来加载它。至于删除已删除的插件,我想您需要跟踪哪些插件添加了哪些路由才能删除它们。
    • 目前我很高兴只加载插件并让它们重新加载应用程序以删除任何内容。目前在我的示例中, /plugins/* 路由应该刷新所有插件。不过会给你答案!
    猜你喜欢
    • 2014-01-13
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    相关资源
    最近更新 更多