0

我有一个 Rails 3.2.6 应用程序,需要您登录才能使用它。它还安装了一个 Rails 引擎/api,为某些部分提供 JSON API,无需身份验证。

当我启动 Rails 服务器并发出以下请求时:

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

一切都按预期工作,API 请求按原样返回 JSON,主页呈现 html 页面。

这是奇怪的部分。如果我在启动 Rails 服务器后立即按此顺序发出请求:

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

然后 API 请求失败。来自根 Rails 应用程序的 before 过滤器为 API 引擎触发,导致重定向到UserSessionsController#newAPI 引擎中不存在的 ,并且失败。如果先向 API 引擎而不是根 Rails 应用程序发出请求,则 API 引擎不会在过滤器之前继承。任何关于这种怪异的启示都会很棒:)

虽然我目前的计划是将 API 引擎变成一个适当的独立 Rack 应用程序。在这一点上,它是引擎的唯一原因似乎是因为在我之前有人真的很喜欢引擎。

4

1 回答 1

1

经过一堆挖掘后,我发现了问题。它与引擎本身有关。我应该指出,我不负责项目的创建,只是现在负责使用它。

假设我们的主机 Rails 应用程序具有...

app/controllers/application_controller.rb

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

我们的引擎被称为 api_engine 并且被隔离在ApiEngine模块下并且具有......

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

你已经知道我要去哪里了吗?问题是 Rails 的动态加载和愚蠢地构建引擎的组合。

当向服务器发出的第一个请求是引擎的PostController时,该post_controller.rb文件是必需的,该文件遇到模块ApplicationController内的常量。ApiEngine但是::ApiEngine::ApplicationController没有定义,所以它检查是否::ApplicationController是,这不是,导致application_controller.rb在引擎中寻找。

但是,如果第一个请求发送到最终定义的主机应用程序,那么ApplicationController当引擎接收到请求时,它只是最终ApplicationController从根应用程序使用,从不需要它自己的类版本。

解决方案非常简单,在引擎lib/api_engine/engine.rb文件中,需要一个config.after_initialize块中正确的应用程序控制器文件:

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

追踪起来有点棘手,特别是处理别人的代码,你倾向于假设某些“基本”的东西正在按他们应该的方式工作。如果其他人发现自己处于类似奇怪的情况,希望这个答案可能有用:)

于 2012-07-12T19:25:06.883 回答