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!
Comments
This has one method hit. How can get access to the cookies method? Which module should I include?