Синатра помощник подделать запрос - PullRequest
6 голосов
/ 29 апреля 2011

Сводка

В веб-приложении Sinatra как я могу сделать виртуальный запрос к приложению и вернуть тело ответа в виде текста?Например, эти маршруты ...

get('/foo'){ "foo" }
get('/bar'){ "#{spoof_request '/foo'} - bar" }

... должны приводить к ответу "foo - bar" при запросе "/ bar" через веб-браузер.

Мотивация

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

Пользователь может редактировать отдельные фрагменты данных на этой странице в интерактивном режиме.Используя мой AJAXFetch jQuery плагин, JavaScript использует AJAX для замены раздела страницы, предназначенного только для чтения (например, имя человека, которому назначена эта ошибка), с частичной формой HTML для редактирования только этого раздела,Пользователь отправляет форму, и AJAX делает новый запрос для статической версии этого поля.

Чтобы быть DRY , я хочу, чтобы представление Haml, создающее страницу, использовалоТочно такой же запрос, который AJAX делает при создании отдельных статических частей.Например:

#notifications.section
  %h2 Email me if someone...
  .section-body= spoof_request "/partial/notifications/#{@bug.id}"

Не совсем рабочий код

Следующий помощник, определяющий spoof_request, работал под Sinatra 1.1.2:

PATH_VARS = %w[ REQUEST_PATH PATH_INFO REQUEST_URI ]
def spoof_request( uri, headers=nil )
  new_env = env.dup 
  PATH_VARS.each{ |k| new_env[k] = uri.to_s } 
  new_env.merge!(headers) if headers
  call( new_env ).last.join 
end

Под Sinatra 1.2.3, однако, это больше не работает.Несмотря на установку каждого из PATH_VARS в желаемый URI, call( new_env ) все еще заставляет Sinatra обрабатывать маршрут для текущего запроса, а не для указанного пути.(Это приводит к бесконечной рекурсии, пока уровень стека, наконец, не достигнет нижнего уровня.)

Этот вопрос отличается от Вызов Синатры изнутри Синатры , поскольку принятый ответ на этот (старый) вопросне поддерживать сеанс пользователя.

Ответы [ 3 ]

4 голосов
/ 04 мая 2011

Код, который я использовал, более сложен, чем ответ в Sinatra README , но опирался на тот же механизм. Ни мой код, ни ответ из README не работали под 1.2.3 из-за ошибки в этой версии. Оба теперь работают под 1.2.6.

Вот тестовый пример простого помощника, который работает:

require 'sinatra'
helpers do
  def local_get(url)
    call(env.merge("PATH_INFO" => url)).last.join
  end
end
get("/foo"){ "foo - #{local_get '/bar'}" }
get("/bar"){ "bar" }

В действии:

phrogz$ curl http://localhost:4567/foo
foo - bar
1 голос
/ 29 апреля 2011

Такое ощущение, что мне не хватает того, что вы пытаетесь сделать, но почему бы просто не вызвать определенный метод?

get('/foo'){ "foo" }
get('/bar'){ "#{self.send("GET /foo")} - bar" }

Кстати, это одно из прикольных названий методов. Не спрашивайте меня, почему это даже разрешено.

PS. Это работает только до версии 1.2.3. DS.

1 голос
/ 29 апреля 2011

Похоже, что в Sinatra 1.2.3 работает следующее:

ENV_COPY  = %w[ REQUEST_METHOD HTTP_COOKIE rack.request.cookie_string
                rack.session rack.session.options rack.input]

# Returns the response body after simulating a request to a particular URL
# Maintains the session of the current user.
# Pass custom headers if you want to set or change them, e.g.
#
#  # Spoof a GET request, even if we happen to be inside a POST
#  html = spoof_request "/partial/assignedto/#{@bug.id}", 'REQUEST_METHOD'=>'GET'
def spoof_request( uri, headers=nil )
  new_env = env.slice(*ENV_COPY).merge({
    "PATH_INFO"    => uri.to_s,
    "HTTP_REFERER" => env["REQUEST_URI"]
  })
  new_env.merge!(headers) if headers
  call( new_env ).last.join 
end

, где Hash#slice определяется как:

class Hash
  def slice(*keys)
    {}.tap{ |h| keys.each{ |k| h[k] = self[k] } }
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...