ruby rackup:是否可以通过编程方式从另一个映射中添加一个映射?

ruby rackup: is it possible to programatically add a mapping from within another mapping?

我有一个 .ru 文件,可以毫无问题地设置映射(下面的 'register' 映射)。

但是我希望服务能够通过点击 url 来注册自己,所以我希望能够从其他映射中即时添加新映射。

下面的代码有效。我做错了什么,这可能吗?

谢谢!

map '/register' do
  run Proc.new { |env|
    # inside of register i want to add another mapping.
    # obviously 'bar' would be a value read out of env
    map '/bar' do
      run Proc.new{ |env| ['200', { 'Content-Type' => 'text/html' },'bar' }
    end

    [ '200', {'Content-Type' => 'text/html'}, "registered"]
  }
end

根据https://rack.github.io/, "To use Rack, provide an "app": 一个object响应调用方法,以环境哈希为参数,返回一个包含三个元素的数组:

  • HTTP 响应代码
  • headers
  • 的哈希值
  • 响应body,必须响应each

您的第三个元素不会响应 each。也许将它包装在一个数组中?

我认为没有办法使用 map 在事后添加路由。一种替代方法是使用 Rack::URLMap 来定义您的应用程序。您需要维护自己的注册路由列表(作为哈希),并在每次向哈希添加新路由时调用 Rack::URLMap#remap

url_map = Rack::URLMap.new
routes = {
  "/register" => lambda do |env|
    routes["/bar"] = lambda do |env|
      [ "200", {"Content-Type" => "text/plain"}, ["bar"] ]
    end

    url_map.remap(routes)

    [ "200", {"Content-Type" => "text/plain"}, ["registered"] ]
  end
}

url_map.remap(routes)
run url_map

请注意,您可以只使用散列,但 URLMap 提供了一些不错的便利,包括 404 处理。如果你有五分钟的空闲时间,它实际上是一个非常好的 class 和 worth reading

如果你愿意,你可以把它变成一个整洁的小东西 class:

class Application
  def initialize
    @routes = {}
    @url_map = Rack::URLMap.new

    register_route "/register" do |env|
      # When "/register" is requested, register the new route "/bar"
      register_route "/bar" do |env|
        [ 200, {"Content-Type" => "text/plain"}, ["bar"] ]
      end
      [ 200, {"Content-Type" => "text/plain"}, ["registered"] ]
    end
  end

  def call(env)
    @url_map.call(env)
  end

  private
  def register_route(path, &block)
    @routes[path] = block
    @url_map.remap(@routes)
  end
end

run Application.new