在 HTTP 上下文之外调度 Rails 控制器操作(不在单元测试中)

Dispatch Rails Controller Action Outside of HTTP context (not in a unit test)

我维护着一个使用 Rails 作为 API 的成熟代码库。 Rails 应用程序还使用 MQTT 做一些事情,MQTT 是一种实时、非 Web、非 HTTP 协议。

一些用户要求能够通过 MQTT 协议模拟相同的 REST 命令(避免需要两次身份验证并拥有两个不同的协议客户端)。

我看过一些项目,such as Facebook's API "simulate" HTTP 通过将部分 HTTP 请求放入使用 JSON 的请求中(例如:有一个 "header" 和 "method" 属性 在 JSON 负载上)。这正是我想要做的,但完全在 HTTP 上下文之外。它将发生在处理 MQTT 消息的后台工作人员中。

是否可以使用 ActionDispatch 和朋友来单独模拟控制器调度?

我很难找到有关如何在 RSpec 之外独立实例化 ActionDispatch::Request 对象的文档。

MyController.dispatch("create",
                     ActionDispatch::Request.new({"???" => "Can't find any docs on this one."}),
                     ActionDispatch::Response.new("?"))
# => RuntimeError: Missing rack.input

哇好有意思的问题!

我的第一个想法是向后处理:所以创建一个假的 Rack::RequestActionDispatch::Request 然后强制处理它?假设它会自动转到正确的控制器和操作(因此您不必显式调用它)。但是当然问题仍然存在:如何创建 Request :)

所以我在浏览 rails 测试时发现了以下可能会让您入门的片段:

SimpleController.action("hello").call(
  "REQUEST_METHOD" => "GET",
  "rack.input" => -> {}
)

来源:https://github.com/rails/rails/blob/85fcb663363cd27220e8bd3136973cc3408cf7d7/actionpack/test/controller/metal_test.rb

根据我的理解,这意味着您可以将整个伪造的请求环境作为哈希值提供,键是字符串,对吧?因此,您可以从有效请求中转储 env 并相应地转置。

不确定这是否真的有用。