【问题标题】:Where do you put your Rack middleware files and requires?您将 Rack 中间件文件和要求放在哪里?
【发布时间】: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 中加载。

【问题讨论】:

    标签: ruby-on-rails conventions rack middleware


    【解决方案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 添加中间件这个看似基本的问题的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-19
      • 2015-03-20
      • 2018-07-19
      • 2015-10-19
      • 1970-01-01
      • 1970-01-01
      • 2013-05-04
      • 1970-01-01
      相关资源
      最近更新 更多