我有一个Rails 3.2.6应用程序,它需要你登录才能使用它。它还有一个安装在/api
上的Rails引擎,它为某些部分提供了JSON API,而不需要身份验证。
当我启动Rails服务器并发出以下请求时:
GET /api/something
GET /
GET /api/something
一切都按预期运行,API请求按预期返回JSON,主页呈现html页面。
奇怪的是。如果我在启动Rails服务器后立即按此顺序发出请求:
GET /
GET /api/something
GET /api/something
则API请求失败。来自根Rails应用程序的before过滤器为应用程序接口引擎触发,导致重定向到在应用程序接口引擎中不存在的UserSessionsController#new
,并失败。如果首先向API引擎而不是根Rails应用程序发出请求,则API引擎不会在筛选器之前继承。对这种怪异现象的任何解释都将是很好的:)
虽然我现在的计划是把API引擎变成一个完全独立的Rack应用程序。似乎在这一点上它是一个引擎的唯一原因是因为在我之前的人真的很喜欢引擎。
发布于 2012-07-12 19:25:07
经过一大堆挖掘,我找到了问题所在。是引擎本身造成的。我应该指出的是,我并不负责项目的创建,只是负责处理它。
假设我们的主机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
文件,该文件会遇到ApiEngine
模块中的ApplicationController
常量。但是::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
这是一个有点棘手的跟踪,特别是处理别人的代码,你倾向于假设某些“基本”的事情是按他们应该的方式工作的。如果其他任何人发现自己处于类似的奇怪情况,希望这个答案可能会有用:)
https://stackoverflow.com/questions/11449464
复制