您将 Rack 中间件文件和需求放在哪里?

问题描述 投票:0回答:8

我正在将 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
中加载。

ruby-on-rails conventions rack middleware
8个回答
48
投票

从 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"

25
投票

您可以将其放入

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
中,当我在代码中引用它时会自动加载。


11
投票

在我的 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
已位于加载路径中,因此该类将正确加载。


5
投票

对于 Rails 3:

#config/application.rb
require 'lib/rack/my_adapter.rb'
module MyApp
  class Application < Rails::Application
    config.middleware.use Rack::MyAdapter
  end
end

0
投票

我不知道有什么约定,但为什么不把它放在

/lib
目录中呢?其中的文件由 Rails 自动加载。


0
投票

您可以创建一个需要必要文件的初始化程序,然后将文件保留在您想要的位置。

根据this,初始化程序在加载机架中间件之前执行。


0
投票

到目前为止,我的工作解决方案是将中间件需求移动到

config/middleware.rb
并在
environment.rb
中需求该文件,将其减少为我可以接受的单个需求。

我仍然想听听其他人是如何解决向 Rails 添加中间件这个看似基本的问题的。


0
投票

已接受的答案不再有效。中间件不应该位于

/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
© www.soinside.com 2019 - 2024. All rights reserved.