Вызов Синатры изнутри Синатры - PullRequest
14 голосов
/ 24 августа 2010

У меня есть сервисное приложение REST на основе Sinatra, и я хотел бы вызвать один из ресурсов внутри одного из маршрутов, эффективно составляя один ресурс из другого. Э.Г.

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

get '/otherresource' do
  # etc.
end

Перенаправление не будет работать, так как мне нужно выполнить некоторую обработку на втором ресурсе и создать из него новый. Очевидно, что я мог бы а) использовать RestClient или какую-либо другую клиентскую среду или б) структурировать мой код так, чтобы вся логика для других ресурсов находилась в методе, и просто вызывать его, однако, кажется, что было бы намного чище, если бы я мог просто перезапустить используйте мои ресурсы из Синатры, используя их DSL.

Ответы [ 5 ]

12 голосов
/ 30 августа 2012

Другой вариант (я знаю, что это не отвечает на ваш фактический вопрос) - поместить ваш общий код (даже шаблонный рендер) в вспомогательный метод, например:

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
9 голосов
/ 05 июля 2014

Документация Синатры охватывает это - по сути, вы используете базовый 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
9 голосов
/ 24 августа 2010

Мне удалось что-то взломать, сделав быстрый и грязный запрос стойки и напрямую вызвав приложение 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, которые вы можете прочитать. Существует Что такое Rack? и Using Rack .

2 голосов
/ 24 августа 2010

Это может или не может применяться в вашем случае, но когда мне нужно было создать такие маршруты, я обычно пробую что-то вроде этого:

%w(main other).each do |uri|
  get "/#{uri}" do
    @res = "hello"
    @res.upcase! if uri == "other"
    @res
  end
end
0 голосов
/ 28 апреля 2014

Опираясь на Ответ AboutRuby , мне нужно было поддерживать выборку статических файлов в lib/public, а также параметры запросов и куки-файлы (для поддержки аутентифицированных сеансов.) Я также решил поднять исключения для ответов не-200(и обрабатывать их в вызывающих функциях).

Если вы отслеживаете метод self.call Синатры в 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...