我正在将 Rails 应用程序中内置的一些逻辑重构为中间件,我遇到的一个烦恼是似乎缺乏将它们放在哪里的约定。
目前我已经决定了
app/middleware
,但我可以轻松地将其移至 vendor/middleware
或者 vendor/plugins/middleware
...
最大的问题是必须需要
config/environment.rb
顶部的各个文件
require "app/middleware/system_message"
require "app/middleware/rack_backstage"
否则我会在
config.middleware.use
行上遇到未初始化的常量错误。这很快就会变得混乱。我宁愿把它藏在初始化程序中的某个地方。
有传统的地方可以放这些东西吗?
我在这个赏金中寻找的具体答案是:我可以把 require 行放在哪里,这样它们就不会弄乱environment.rb文件,但仍然在 config.middleware.use 调用之前加载?我拥有的一切尝试过会导致未初始化的常量错误。
更新:现在我们正在使用 Rails 3.0,我将 Rails 应用程序视为任何其他 Rack 应用程序;中间件的代码文件放入
lib
(或 Gemfile
中列出的 gem),并且需要并在 config.ru
中加载。
从 Rails 3.2 开始,Rack 中间件属于 app/middleware 目录。
它“开箱即用”,无需任何明确的 require 语句。
简单示例:
我正在使用一个名为 CanonicalHost 的中间件类,它是在 app/middleware/canonical_host.rb 中实现的。我已将以下行添加到 production.rb (注意,中间件类是明确给出的,而不是作为带引号的字符串,这适用于任何特定于环境的配置文件):
config.middleware.use CanonicalHost, "example.com"
如果您要向 application.rb 添加中间件,则需要根据 @mltsy 的评论添加引号。
config.middleware.use "CanonicalHost", "example.com"
您可以将其放入
lib/tableized/file_name.rb
。只要您尝试加载的类可以通过其文件名发现,Rails 就会自动加载所需的文件。因此,例如:
config.middleware.use "MyApp::TotallyAwesomeMiddleware"
你会留在:
lib/my_app/totally_awesome_middleware.rb
Rails 捕获 const_missing 并尝试自动加载与缺失常量相对应的文件。只要确保你们的名字匹配并且你们是肉汁即可。 Rails 甚至提供了漂亮的助手,可以帮助您轻松识别文件的路径:
>> ChrisHeald::StdLib.to_s.tableize.singularize
=> "chris_heald/std_lib"
所以我的 stdlib 位于
lib/chris_heald/std_lib.rb
中,当我在代码中引用它时会自动加载。
在我的 Rails 3.2 应用程序中,我可以通过将中间件
TrafficCop
放置在 app/middleware/traffic_cop.rb
来加载,就像 @MikeJarema 所描述的那样。然后我按照指示将这一行添加到我的config/application.rb
中:
config.middleware.use TrafficCop
但是,应用程序启动后,我不断收到此错误:
uninitialized constant MyApp::Application::TrafficCop
显式指定根命名空间也没有帮助:
config.middleware.use ::TrafficCop
# uninitialized constant TrafficCop
出于某种原因(我尚未发现),在 Rails 生命周期的此时,
app/middleware
并未包含在加载路径中。如果我删除 config.middleware.use
行并运行控制台,我可以毫无问题地访问 TrafficCop
常量。但在配置时在app/middleware
中找不到它。
我通过将中间件类名称括在引号中来修复此问题,如下所示:
config.middleware.use "TrafficCop"
这样,我就可以避免
uninitialized constant
错误,因为 Rails 还没有尝试找到 TrafficCop
类。但是,当它开始构建中间件堆栈时,它将常量化该字符串。此时,app/middleware
已位于加载路径中,因此该类将正确加载。
对于 Rails 3:
#config/application.rb
require 'lib/rack/my_adapter.rb'
module MyApp
class Application < Rails::Application
config.middleware.use Rack::MyAdapter
end
end
我不知道有什么约定,但为什么不把它放在
/lib
目录中呢?其中的文件由 Rails 自动加载。
您可以创建一个需要必要文件的初始化程序,然后将文件保留在您想要的位置。
根据this,初始化程序在加载机架中间件之前执行。
到目前为止,我的工作解决方案是将中间件需求移动到
config/middleware.rb
并在 environment.rb
中需求该文件,将其减少为我可以接受的单个需求。
我仍然想听听其他人是如何解决向 Rails 添加中间件这个看似基本的问题的。
已接受的答案不再有效。中间件不应该位于
/app
中,因为它们无法重新加载。
它们应该位于
/lib
中并显式加载,例如
/lib/middleware/system_message.rb
module Middleware
class SystemMessage
# ...
end
end
/config/application.rb
require_relative '../lib/middleware/system_message'
# ...
config.middleware.use Middleware::SystemMessage