0

I have a Rails 3.2.6 application which requires you to login to use it. It also has an Rails Engine mounted to /api which provides a JSON API to certain parts, without requiring authentication.

When I kick up the Rails server and make the following requests:

GET /api/something
GET /
GET /api/something

Everything works as expected, the API requests returns JSON as they should, the home page renders the html page.

Here's the weird part. If I make the requests in this order right after starting the Rails server:

GET /
GET /api/something
GET /api/something

Then the API requests fail. The before filters from the root Rails app fire for the API engine, causing a redirect to UserSessionsController#new, which doesn't exist in the API engine, and fails. While if make a request to the API engine first instead of the root Rails app, the API engine does not inherit before filters. Any light shed on this weirdness would be great :)

Though my current plan is to turn the API engine into a properly self-contained Rack app. It seems the only reason it's an engine at this point is cause someone before me really liked engines.

jimeh
  • 1,391
  • 1
  • 16
  • 32
  • As I understood correctly: you seems to have some `before_filter :authenticate_user` in Root app, is it correct? – bor1s Jul 12 '12 at 14:10

1 Answers1

1

After a bunch of digging through I have found the issue. It was with the Engine itself. I should point out that I'm not responsible for the project's creation, just now responsible for working with it.

Lets say our host Rails app has...

app/controllers/application_controller.rb:

class ApplicationController < ActionController::Base
  before_filter :foo_bar
  layout :application
end

And our engine is called api_engine and isolated under the ApiEngine module and has...

app/controllers/api_engine/application_controller.rb:

module ApiEngine
  class ApplicationController < ActionController::Base
    layout false
  end
end

app/controllers/api_engine/post_controller.rb:

module ApiEngine
  class PostController < ApplicationController
    # code goes here...
  end
end

Do you already see where I'm going with this? The problem is a combination of Rails' dynamic loading, and stupidly structuring the engine.

When the first request made to the server is to the engine's PostController, the post_controller.rb file is required, which comes across the ApplicationController constant within the ApiEngine module. But ::ApiEngine::ApplicationController is not defined, so it checks if ::ApplicationController is, which at this it is not, causing is to go looking for application_controller.rb within the engine.

However, if the first request goes to the host app, which ends up defining ApplicationController, when the engine receives a request, it simply ends up using ApplicationController from the root app, never requiring it's own version of the class.

The solution is decently simple, in the engine's lib/api_engine/engine.rb file, require the correct application controller file within a config.after_initialize block:

module ApiEngine
  class Engine < Rails::Engine
    isolate_namespace ApiEngine
    config.after_initialize do
      require "api_engine/application_controller"
    end
  end
end

It was a bit tricky to track down, specially dealing with someone else's code, you tend to assume certain "basic" things are working as they should. Hopefully this answer might be useful should anyone else ever find themselves in a similarly weird situation :)

jimeh
  • 1,391
  • 1
  • 16
  • 32