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

Posted

技术标签:

【中文标题】您将 Rack 中间件文件和要求放在哪里?【英文标题】:Where do you put your Rack middleware files and requires? 【发布时间】:2011-03-26 14:15:57 【问题描述】:

我正在将 Rails 应用程序中内置的一些逻辑重构为中间件,我遇到的一个烦恼是似乎缺乏放置它们的约定。

目前我已选择app/middleware,但我可以轻松地将其移至vendor/middlewarevendor/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 中加载。

【问题讨论】:

【参考方案1】:

从 Rails 3.2 开始,Rack 中间件属于 app/middleware 目录。

它“开箱即用”,无需任何明确的 require 语句。

快速示例:

我正在使用一个名为 CanonicalHost 的中间件类,它在 app/middleware/canonical_host.rb 中实现。我在 production.rb 中添加了以下行(注意中间件类是明确给出的,而不是作为引用字符串,它适用于任何特定于环境的配置文件):

config.middleware.use CanonicalHost, "example.com"

如果您要向 application.rb 添加中间件,则需要根据@mltsy's comment 包含引号。

config.middleware.use "CanonicalHost", "example.com"

【讨论】:

能否添加任何链接以供参考?它对我来说不是开箱即用的,而且 Google / Rails 指南也没有帮助......谢谢! 在我意识到我犯了一个愚蠢的错误,将它放在我的根文件夹而不是(已经指定的)应用程序文件夹中之后,我得到了这个开箱即用的工作。所以,foo_app/app/middleware/file.rb. 我必须用引号将我的中间件类名括起来才能让它工作;请参阅下面的答案。 注意:只有在特定环境文件(即production.rb)中添加中间件时,这才有效(不带引号) - 如果您想通过将其添加到所有环境中将其添加到 @ 987654326@,您必须使用引号(或明确要求定义您的类的文件),因为 application.rb 是首先加载的内容之一 - 在任何动态初始化代码加载 app/middleware 文件之前。跨度> 注意,在 Rails 5+ 中,您不能再使用字符串作为中间件的名称。您需要使用正确的类名。此外,根据@rafaelfranca(Rails 核心)的说法,“中间件不能在应用程序中,因为它们无法重新加载。它们应该在 lib 中,如果你将它们放在 lib 中,require_relative 将起作用。” i> github.com/rails/rails/issues/25525#issuecomment-479941866【参考方案2】:

你可以把它放在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"

所以我的标准库位于lib/chris_heald/std_lib.rb,当我在代码中引用它时会自动加载。

【讨论】:

我有一些名为Rack::Backstage 的中间件。把它放在lib/rack/backstage.rb。初始化常量错误。 仅在第一个参数是字符串时有效。一旦我想通了,成功!【参考方案3】:

在我的 Rails 3.2 应用程序中,正如@MikeJarema 所述,我可以通过将中间件TrafficCop 放在app/middleware/traffic_cop.rb 来加载它。然后我按照指示将此行添加到我的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.2.18 上,当我把它放在 application.rb 中时遇到同样的问题 - 但是当我把它放在特定的环境配置中时,它工作得很好!如果您遵循以 config.ru 开头的加载路径,结果是 application.rb 在大多数其他内容之前加载,然后应用程序被初始化(它加载所有动态初始化程序,包括中间件),其他环境文件在之后加载那个,所以到那时中间件常量就定义好了! 注意,在 Rails 5+ 中,您不能再使用字符串作为中间件的名称。您需要使用正确的类名。此外,根据@rafaelfranca(Rails 核心)的说法,“中间件不能在应用程序中,因为它们无法重新加载。它们应该在 lib 中,如果你将它们放在 lib 中,require_relative 将起作用。” i> github.com/rails/rails/issues/25525#issuecomment-479941866【参考方案4】:

对于 Rails 3:

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

【讨论】:

这仍然有效 - 并且比所有其他字符串答案更好 - 在 Rails 5+ 中,他们不允许使用字符串作为中间件的名称。【参考方案5】:

我不知道约定,但为什么不把它放在/lib 目录中呢? Rails 会自动加载其中的文件。

【讨论】:

直到 environment.rb 运行之后,如果有的话。将它们移动到 lib 并不能解决未初始化的常量错误。【参考方案6】:

您可以创建一个需要必要文件的初始化程序,然后将文件放在您想要的任何地方。

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

【讨论】:

看起来我在阅读时有点乐观。我猜 config.ru 也不符合你的要求? 嗯,这需要使用 rackup 而不是脚本/服务器,对吧?如果必须,我可以这样做,但老实说,我认为这会比这更容易。【参考方案7】:

到目前为止,我的工作解决方案是将中间件要求移至 config/middleware.rb 并要求 environment.rb 中的文件,将其减少为我可以接受的单个要求。

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

【讨论】:

以上是关于您将 Rack 中间件文件和要求放在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

理解 Rack 应用及其中间件

iOS 8 JavaScriptCore:您将 JavaScript 文件放在哪里?

在 Ruby on Rails 的上下文中引用时,啥是中间件?

用PHP设计一个函数,要求将数字数组中所有奇数放在左边,0放在中间,偶数放在右边。

pr转场音效放在哪个文件夹?

金蝶天燕中间拒绝putdelete请求解决方案