Difference between use and run in Rack - ruby

What's the difference between the use and run methods in rackup files? It seems run is always at the end of config.ru, but it seems as if you should just be able to use use. Enlightening resources would also be very much appreciated.

use is for middlewares
class MyCustomMiddleware
def initialize(app)
#app = app
end
def call(env)
if condition
env['set-header'] = 'Middleware Can modify the response & pass it into next middleware'
end
#app.call(env)
end
run takes an argument that responds to call and returns a final Rack response with a HTTP Response code like 200.
class MyApp
def self.call(env)
[200, { "Content-Type" => "text/html" }, ["OK"]]
end
end
To understand the difference between use & run. lets see structure of typically rack app.
Typical Rack App
Rack app includes multiple middleware(s) which respond to call but do not return final rack response & an Object that responds to call which returns final rack response which includes HTTP response code(200,404, 500 etc). so typically there will be multiple objects which act as middlewares & then a object which returns final rack response with response code.
Difference between use & run
Now with this,
it seems can we can invoke use multiple times, once for each middleware & run only once in a single Rack App. so use will only invoke a middleware, while run will run the rack object which will return final rack response with HTTP status code.
example config.ru
use MyCustomMiddleware
use MyCustomMiddleware2
use MyCustomMiddleware3
run MyApp
In case if anything above is wrong, Let me know. So I can correct it.

Related

sinatra routes first path param is a number

I want to be able to match a route that looks something like
/2/monkey/session
I have the following in sinatra but
/:version_number/:name/session
And I keep getting the Sinatra doesn’t know this ditty. Anyone knows a way to getting this to work so that I can have params[:version_number] and params[:name] matched.
I wrote the code below (Ruby 2.0.0 / Sinatra 1.4.3).
require "sinatra"
get "/:version_number/:name/session" do
params.inspect
end
The response seems like correctly.
{"splat"=>[], "captures"=>["2", "monkey"], "version_number"=>"2", "name"=>"monkey"}
Why don't you check HTTP method or comment out other code?

Sinatra app that redirects POST/GET requests with parameters

I'm migrating servers but unfortunately the old server IP is hardcoded inside my iPhone app. Obviously I'm going to submit an update that sets the API endpoint to my new server, but in the meantime I need to setup an app on the old server that redirects all the requests to the new server. I've heard Sinatra would be perfect for this.
require 'sinatra'
get "/foo/bar" do
redirect "http://new-server.com/foo/bar", 303
end
post "/foo/bar" do
redirect "http://new-server.com/foo/bar", 303
end
The problem is that these do not forward the GET or POST parameters along with the request. I read on the Sinatra doc that you can do that by putting them in the URL directly (works for GET requests), or by setting session variables.
Is manually parsing and formatting the GET params to put them back into the redirect URL the only way to go for GET redirects? How are you supposed to forward POST parameters?
For GET requests, use request.fullpath or request.query_string. For POST request, use status code 307, so the subsequent request will be a POST with the same parameters.
helpers do
def new_url
"http://new-server.com" + request.fullpath
end
end
get "/foo/bar" do
redirect new_url
end
post "/foo/bar" do
redirect new_url, 307
end
I would overload the Hash class in lib/overload_hash.rb, like so:
class Hash
def to_url_params
elements = []
keys.size.times do |i|
elements << "#{keys[i]}=#{values[i]}"
end
elements.join('&')
end
end
EDIT (Better solution using net / http)
Place a require "lib/overload_hash", require "net/http" and require "uri" under require 'sinatra'. The following example can be translated into GET easily.
post '/foo/bar' do
uri = URI.parse("http://example.com/search")
response = Net::HTTP.post_form(uri, params.to_ur_params)
response
end

Ruby Sinatra: Can I update a view template multiple times within one client request

I want to do this:
get '/test' do
#dog = 'WOOF'
erb :test
sleep(1)
#dog = 'BOWWOW'
erb :test
sleep(1)
#dog = 'ARF'
erb :test
end
Is it possible to do something like this where the client sees each update or no, I've tried but can't get it to work.
In short: no.
I think you're confusing the way HTTP works. First, HTTP is stateless. This means that multiple requests know nothing about each other (this is mitigated by the use of sessions via cookies, or possibly HTTP basic auth).
Further, you cannot resend the HTTP body like you're doing. Once it's sent there's no going back. Techniques like long-polling delay sending the body so they can send it whenever they like, but once they send something the request is complete and a new one must be started. Thus, once you've rendered the body once via erb, you're request is finished.
What it seems like you're trying to achieve can only be done via Javascript with AJAX, or with completely separate full-page requests.

How can I block on an EventMachine deferrable object?

I'm making a request to another server as part of a POST method to my Sinatra application. The library I'm using to make the request is an EventMachine library that immediately returns an EM::Deferrable object when a request is made, but I need to block in the controller method until the asynchronous request completes so I can return a partial with data returned in the request. What's the best approach for doing this?
One solution would be to use async_sinatra and an EM based webserver like Thin. With async_sinatra you would have a body method for explicit rendering. It would work like this:
require 'sinatra/async'
require 'em-http-request'
class Application < Sinatra::Base
register Sinatra::Async
apost '/' do
http = EM::HttpRequest.new('http://www.google.de/').get
http.callback do
body do
# your http processing in here, will be rendered
end
end
http.errback do
body { 'error' }
end
end
end
When you block on an evented API, you get worst of the two worlds.
I would try to avoid calls through EM in favor of more 'traditional' methods (a-la curl).
If this is not possible, then I would return an empty partial and have client poll the server for updates.

Using Cookies with Rack::Test

I'm trying to write RSpec tests for my Sinatra application using Rack::Test. I can't understand how I can use cookies. For example if my application set cookies (not via :session) how can I check whether that cookie is properly set?
Also, how can I send requests with that cookie?
Rack::Test keeps a cookie jar that persists over requests. You can access it with rack_mock_session.cookies. Let's say you have a handler like this:
get '/cookie/set' do
response.set_cookie "foo", :value => "bar"
end
Now you could test it with something like this:
it 'defines a cookie' do
get '/'
rack_mock_session.cookie_jar["foo"].should == "bar"
end
You can also access cookies with last_request.cookies, but as the name says, it contains the cookies for the last request, not the response. You can set cookies with set_cookie and clear them with clear_cookies.
it 'shows how to set a cookie' do
clear_cookies
set_cookie "foo=quux"
get '/'
last_request.cookies.should == {"foo" => "quux"}
end
Update: If you want the cookie jar to persist across the test cases (it blocks), you need to initialize the Rack session before executing any test cases. To do so, add this before hook to your describe block.
before :all do
clear_cookies
end
Alternative, you could for example use before :each to set up the necessary cookies before each request.

Resources