Summary
Within a Sinatra web app, how can I make a virtual request to the application and get the response body back as text? For example, these routes...
get('/foo'){ "foo" }
get('/bar'){ "#{spoof_request '/foo'} - bar" }
...should result in the response "foo - bar" when requesting "/bar" with the web browser.
Motivation
My application has a page representing an bug entry, with lots of details about that bug entry: what version was the bug experienced in, how important is it, what tags are associated with it, to whom is the bug assigned, etc.
The user may edit individual pieces of data on this page interactively. Using my AJAXFetch jQuery plugin, JavaScript uses AJAX to swap out a read-only section of the page (e.g. the name of the person that this bug is assigned to) with an HTML partial form for editing just that section. The user submits the form, and AJAX makes a new request for the static version of that field.
In order to be DRY, I want the Haml view that creates the page to use the exact same request that AJAX makes when creating the individual static pieces. For example:
#notifications.section
%h2 Email me if someone...
.section-body= spoof_request "/partial/notifications/#{@bug.id}"
Not-Quite-Working Code
The following helper defining spoof_request
worked under 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
Under Sinatra 1.2.3, however, this no longer works. Despite setting each of the PATH_VARS
to the desired URI, the call( new_env )
still causes Sinatra to process the route for the current request, not for the specified path. (This results in infinite recursion until the stack level finally bottoms out.)
This question differs from Calling Sinatra from within Sinatra because the accepted answer to that (old) question does not maintain the session of the user.
The following appears to work as needed under Sinatra 1.2.3:
where
Hash#slice
is defined as:It feels like I'm missing what you are trying to do but why not just call the defined method?
That is one funky method name by the way. Don't ask me why it's even allowed.
PS. This only works pre version 1.2.3. DS.
The code I was using is more complex than the answer in the Sinatra README, but relied on the same mechanism. Neither my code nor the answer from the README worked under 1.2.3 due to a bug in that version. Both now work under 1.2.6.
Here's a test case of a simple helper that works:
In action: