在Sinatra内召唤Sinatra

时间:2010-08-23 21:13:00

标签: ruby sinatra

我有一个基于Sinatra的REST服务应用程序,我想从其中一个路由中调用其中一个资源,从而有效地组合另一个资源。 E.g。

get '/someresource' do
  otherresource = get '/otherresource'
  # do something with otherresource, return a new resource
end

get '/otherresource' do
  # etc.
end

重定向不起作用,因为我需要对第二个资源进行一些处理并从中创建一个新的。显然我可以a)使用RestClient或其他一些客户端框架或b)构造我的代码所以其他资源的所有逻辑都在一个方法中然后调用它,但是,感觉如果我可以重新使用他们的DSL从Sinatra内部使用我的资源。

5 个答案:

答案 0 :(得分:12)

另一个选项(我知道这不是回答你的实际问题)是将你的公共代码(甚至是模板渲染)放在一个辅助方法中,例如:

helpers do
  def common_code( layout = true )
    @title = 'common'
    erb :common, :layout => layout
  end
end

get '/foo' do
  @subtitle = 'foo'
  common_code
end

get '/bar' do
  @subtitle = 'bar'
  common_code
end

get '/baz' do
  @subtitle = 'baz'
  @common_snippet = common_code( false )
  erb :large_page_with_common_snippet_injected
end

答案 1 :(得分:9)

我能够通过快速而脏的机架请求并直接调用Sinatra(机架应用程序)应用程序来解决问题。它不漂亮,但它的工作原理。请注意,将生成此资源的代码提取到辅助方法而不是执行此类操作可能会更好。但这是可能的,并且可能有更好,更清洁的方式来做这件事。

#!/usr/bin/env ruby
require 'rubygems'
require 'stringio'
require 'sinatra'

get '/someresource' do
  resource = self.call(
    'REQUEST_METHOD' => 'GET',
    'PATH_INFO' => '/otherresource',
    'rack.input' => StringIO.new
  )[2].join('')

  resource.upcase
end

get '/otherresource' do
  "test"
end

如果你想了解更多关于幕后发生的事情,我写了几篇关于你可以阅读的Rack基础知识的文章。有What is Rack?Using Rack

答案 2 :(得分:9)

Sinatra的文档涵盖了这一点 - 基本上您使用基础rack界面的call方法:

http://www.sinatrarb.com/intro.html#Triggering%20Another%20Route

触发另一条路线

  

有时传球不是你想要的,而是   你想得到调用另一条路线的结果。简单地使用   呼吁实现这一目标:

get '/foo' do
  status, headers, body = call env.merge("PATH_INFO" => '/bar')
  [status, headers, body.map(&:upcase)]
end

get '/bar' do
  "bar"
end

答案 3 :(得分:2)

这可能适用于您的情况,也可能不适用,但是当我需要创建这样的路线时,我通常会尝试这些方法:

%w(main other).each do |uri|
  get "/#{uri}" do
    @res = "hello"
    @res.upcase! if uri == "other"
    @res
  end
end

答案 4 :(得分:0)

AboutRuby's answer的基础上,我需要支持在lib/public中获取静态文件以及查询参数和cookie(用于维护经过身份验证的会话。)我还选择在非200响应中引发异常(并在调用函数中处理它们。

如果您在self.call中跟踪Sinatra的sinatra/base.rb方法,则需要env参数并使用它构建Rack::Request,因此您可以在那里挖掘以查看参数得到支持。

我不记得返回语句的所有条件(我认为有一些Ruby 2更改),所以请随意调整您的要求。

这是我正在使用的功能:

  def get_route url
    fn = File.join(File.dirname(__FILE__), 'public'+url)
    return File.read(fn) if (File.exist?fn)

    base_url, query = url.split('?')
    begin
      result = self.call('REQUEST_METHOD' => 'GET',
                         'PATH_INFO' => base_url,
                         'QUERY_STRING' => query,
                         'rack.input' => StringIO.new,
                         'HTTP_COOKIE' => @env['HTTP_COOKIE'] # Pass auth credentials
                         )
    rescue Exception=>e
      puts "Exception when fetching self route: #{url}"
      raise e
    end
    raise "Error when fetching self route: #{url}" unless result[0]==200 # status

    return File.read(result[2].path) if result[2].is_a? Rack::File
    return result[2].join('') rescue result[2].to_json
  end