>
Our Rails3 (beta4) application had one route mapped in config/routes to a Sinatra app, by means of the following route:
match '/foo', :to => EndPointApp, :as => :endpoint
The route was being defined to run as a Sinatra Application
require 'sinatra'
class EndPointApp < Sinatra::Application
post '/foo' do
...
end
end
This was working mostly fine, but it was returning Set-Cookie header with the standard Rails sessions cookie, which in this case was preventing the client of this endpoint from successfully interpreting the result. As I could do nothing about the client side, I had to remove Set-Cookie from the headers, but only for this end-point and obviously not from the entire app. This proved to be somewhat more complicated than I had hoped, so let me share the solution here in hopes it might save someone else an hour or two.
First, I ran “rake middleware” and observed the following Rack stack:
use ActionDispatch::Static use Rack::Lock use ActiveSupport::Cache::Strategy::LocalCache use Rack::Runtime use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::RemoteIp use Rack::Sendfile use ActionDispatch::Callbacks use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ParamsParser use Rack::MethodOverride use ActionDispatch::Head run Kigster::Application.routes
As can be immediately seen from here, the routes execute very last after Session::CookieStore already wrapped the request. OK, so looks like I need to bypass the routes somehow, and so I started to look at Rails::Metal, which is supposed to run before all other processing.
Once I started to look for Rails::Metal, I realized pretty quickly that I am missing metal generator:
> rails g metal Could not find generator metal.
After a few more rounds of digging around, it turns out that in Rails3 Beta4 Rails::Metal has been completely removed, because it is no longer needed in a Rack environment.
So I had convert my Sinatra module to a Rack module, and insert it into the Rack middleware stack before the Cookie/Sessions:
require File.expand_path('../../../config/environment', __FILE__) unless defined?(Rails)
module Kigster
class EndPoint
def initialize(app)
@app = app
end
def call(env)
if env["PATH_INFO"] =~ /^foo/
process_request(env)
else
@app.call(env)
end
end
private
def process_request(env)
req = Rack::Request.new(env)
params = req.params
# do stuff
[ 200,
{ "Content-Type" => "text/html",
"Content-Length" => "0" },
[""]
]
end
end
end
I had add the following to my config/application.rb to enable this Rack module, and have it run before the ActionDispatch::Session::CookieStore:
# config/application.rb
# require the file directly
require File.join(File.dirname(__FILE__), '../app/metal/kigster_endpoint')
....
module Kigster
class Application < Rails::Application
config.middleware.insert_after Rails::Rack::Logger,
Kigster::EndPoint
end
end
Now my handler executes before the session, and the result does not include Set-Cookie header.
Any other suggestions on how to make this any simpler, or more correct are as always welcome!