在Sinatra网络应用中,如何向应用程序发出虚拟请求并将响应正文作为文本返回?例如,这些路线......
get('/foo'){ "foo" }
get('/bar'){ "#{spoof_request '/foo'} - bar" }
...在使用网络浏览器请求“/ bar”时,应该会产生响应“foo - 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处理当前请求的路由,而不是指定的路径。 (这导致无限递归,直到堆栈级别最终达到最低点。)
此问题与Calling Sinatra from within Sinatra不同,因为该(旧)问题的已接受答案不会维护用户的会话。
答案 0 :(得分:4)
我使用的代码比answer in the 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 :(得分:1)
以下似乎可以在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
答案 2 :(得分:1)
感觉我错过了你想要做的事,但为什么不调用定义的方法?
get('/foo'){ "foo" }
get('/bar'){ "#{self.send("GET /foo")} - bar" }
顺便提一下,这是一个时髦的方法名称。不要问我为什么甚至允许它。
PS。这仅适用于1.2.3之前的版本。 DS。