1

I am using Ruby on Rails 3 and I would like to route some URLs to some Rack middlewares. That is, if a user try to browse at http://<my_site_name>.com/api/user/1 the system should consider to run before a Rack file and then proceed in the request.

I have a Rack::Api:User located in the lib/rack/api/user folder.

From the RoR official documentation I discovered this:

     Mount a Rack-based application to be used within the application.

       mount SomeRackApp, :at => "some_route"

     Alternatively:

       mount(SomeRackApp => "some_route")

     All mounted applications come with routing helpers to access them.
     These are named after the class specified, so for the above example
     the helper is either +some_rack_app_path+ or +some_rack_app_url+.
     To customize this helper's name, use the +:as+ option:

       mount(SomeRackApp => "some_route", :as => "exciting")

     This will generate the +exciting_path+ and +exciting_url+ helpers
     which can be used to navigate to this mounted app.

In the routers.rb file I tryed

mount "Rack::Api::User", :at => "/api/user/1"
# => ArgumentError missing :action

scope "/api/user/1" do
  mount "Rack::Api::User"
end
# => NoMethodError undefined method `find' for "Rack::Api::User

I also tryed

match '/api/user/1' => Rack::Api::User
# => Routing Error No route matches "/api/user/1"

match '/api/user/1', :to => Rack::Api::User
# ArgumentError missing :controller

but no one works.


UPDATE

My Rack file is something like this:

  module Api
    class User

      def initialize(app)
        @app = app
      end

      def call(env)
        if env["PATH_INFO"] =~ /^\/api\/user\/i
          ...
        else
          @app.call(env)
        end
      end
    end
 end
user502052
  • 14,803
  • 30
  • 109
  • 188

1 Answers1

3

Assuming you're require-ing your Rack app somewhere in your bootup process, like in an initializer (keep in mind that files from lib are not automatically loaded anymore unless you write code to do so! see this SO answer for more), then try mounting it without quotes. For example, instead of:

mount "Rack::Api::User", :at => "/api/user/1"

try

mount Rack::Api::User, :at => "/api/user/1"

[Update]

Here is a link to the changes I made to a basic Rails application that demonstrates both autoloading and mounting a Rack application: https://github.com/BinaryMuse/so_5100999/compare/master...rack

[Update 2]

Ah, I see what you're saying now. You want a middleware. I've updated the code at the above URL to implement your application as middleware. config/initializers/rack.rb is the file that loads and inserts the middleware. Hope this is what you're looking for!

Community
  • 1
  • 1
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • Can you make a real example? If my rack file is in '/lib/api/user/', how and where I must 'require' that? P.S.: I wrote code to load the 'lib' path in the 'application.rb' file ('config.autoload_paths += %W(#{config.root}/lib)'). P.S. II: I updated the question. P.S.: I tryed your code, but I get same errors. – user502052 Feb 24 '11 at 20:06
  • If I'm not mistaken, if you want to autoload Rack::Api::User, then the class should be defined in `lib/rack/api/user.rb`. In any case, you can load the file manually by creating a file in `config/initializers/load_my_rack_app.rb` (anything in `config/initializers` is loaded automatically) and put in the code `require "lib/api/user/whatever.rb"`. – Michelle Tilley Feb 24 '11 at 20:22
  • But I get a 'missing :controller'. Is that for the rack statement in the 'user.rb' file? – user502052 Feb 24 '11 at 22:03
  • @user502052: I've updated my answer with a link to some working code that may help. – Michelle Tilley Feb 24 '11 at 23:13
  • 1
    You are great! However the problem, as I suspected, was in the rack statement: I used 'call' instead of 'self.call' and also 'def initialize(app) ...' that (how you wrote in your code) must not be in the code. The only thing that I don't understand is: why use 'self.call' instead of common 'initialize'/'call' methods? And why 'SCRIPT_NAME' instead of 'PATH_INFO'? – user502052 Feb 24 '11 at 23:57
  • However, now I can not handle anymore incoming request from client applications. I think because in your code there isn't the 'def initialize(app) @app = app end' statement. In fact I don't have anymore access to 'env["HTTP_VARIABLES"]' of incoming requests. – user502052 Feb 25 '11 at 00:20
  • I'm following you now. I've updated my answer; I think this is what you're talking about. – Michelle Tilley Feb 25 '11 at 01:02
  • I would like to have a middleware that works both for client and service applications. I opened another question: http://stackoverflow.com/questions/5112479/rack-managing-client-and-service-application-responses – user502052 Feb 25 '11 at 01:19
  • However, in your new code, a request from outside works, but not from "inside" (see the new question). – user502052 Feb 25 '11 at 01:36