【问题标题】:How can I access an ActiveStorage object via URL in a test environment?如何在测试环境中通过 URL 访问 ActiveStorage 对象?
【发布时间】:2018-08-29 07:31:55
【问题描述】:

给定一个具有 ActiveStorage 附件的模型

class MyObject
  has_one_attached :avatar
end

在开发环境中,我可以将头像作为 StringIO 对象检索。

obj = MyObject.new( { valid params } )
file = File.open( Rails.root.join( "spec/support/images/test_image.jpg" ))
obj.avatar.attach( io: file, filename: "test_image.jpg" )
obj.save

version = obj.avatar.variant( resize: '200x200>').processed
version_url = Rails.application.routes.url_helpers.url_for( version )
download = open(version_url)
download.class 
=> StringIO

当我尝试在测试环境中做同样的想法时,open(version_url) 返回

Errno::ECONNREFUSED Exception: Failed to open TCP connection to localhost:3000 (Connection refused - connect(2) for "localhost" port 3000)

有没有人在测试中成功下载了 activestorage 附件?我应该如何配置测试环境来实现这一点?

我的测试环境已经有了

config.active_storage.service = :test
Rails.application.routes.default_url_options = {host: "localhost:3000"}

我忽略了什么?

编辑

#storage.yml
test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

【问题讨论】:

  • 可能是这一行:config.active_storage.service = :test 吗?我相信service 应该是您的storage.yml 文件中定义的服务之一,而不是您正在运行的环境。所以config.active_storage.service = :local 或它在开发中设置的任何东西都可以解决它。
  • 感谢@rparr。我在 storage.yml 中定义了以下内容。这应该足够了吗? test: service: Disk root: &lt;%= Rails.root.join("tmp/storage") %&gt;
  • 嗯,如果这是在您的 storage.yml 文件中定义的,那么也许这不是问题。您是否有可能让您的开发服务器在localhost:3000 同时运行测试?这可能是两个进程争夺同一个端口的错误。
  • 我不认为是端口。至少,将 test.rb default_url_options 更改为“localhost:4999”并没有解决问题。还有什么我应该在这里尝试的吗?
  • 我想不出别的办法了。但您可能想看看 Carlos Ramirez III 的答案。

标签: ruby-on-rails rails-activestorage


【解决方案1】:

通过 Rails 应用服务器访问存储的文件

活动存储附件生成指向应用程序的 URL。然后应用程序 URL 端点重定向到真实文件。这将文件的物理位置与 URL 分离,并提供对镜像等功能有用的间接性。

这也意味着为了使用生成的 URL 访问文件,必须运行 Rails 应用程序服务器...

服务器不在测试环境中运行

Rails 测试套件在运行测试时不会启动服务器。测试通常不需要一个即可运行。

Errno::ECONNREFUSED Exception: Failed to open TCP connection to localhost:3000 (Connection refused - connect(2) for "localhost" port 3000)

出现此错误是因为open 调用尝试在服务器位置localhost:3000 请求文件。因为没有服务器在运行,所以它失败了。

即使启动开发服务器,它仍然会失败,因为 Active Storage AttachmentBlob 记录存储在测试数据库中,而不是开发数据库中。

绕过应用服务器,直接获取文件路径

为了访问测试套件中的文件或变体,您需要绕过应用程序服务器并获取磁盘上文件的直接路径。

Active Storage 测试套件源代码向我们展示了如何做到这一点:

blob_or_variant.service.send(:path_for, blob_or_variant.key)

View Source

这将返回一个文件路径(在磁盘上),然后您可以使用File.open 打开它。

修正上面的例子

在上面的例子中,改变

download = open(version_url) # BAD: tries to access using HTTP

download = File.open( version.service.send(:path_for, version.key) )

在测试套件中使用存根来避免网络请求

如果您正在测试使用 HTTP 访问文件的代码,最好将网络调用存根以完全避免它。

这里有一些关于如何在 RSpec 中执行此操作的很好示例:
RSpec how to stub open?

【讨论】:

  • 感谢@carlos,这很有意义并且看起来很有希望。我会试一试并报告。一个最初的问题 - 我认为version.service.send..... 不是不是在非测试环境中执行此操作的最佳方法是否正确? (不利用 CDN 镜像等)。我正在考虑如何将它集成到我的代码中 - download = open(version_url) 不在测试中,所以我猜这个类需要根据 ENV 运行不同的代码
  • 我想我在问,version.service.... 方法在非测试环境中的缺点是什么?
  • 啊,我明白了。如果代码最终将存在于非测试环境中,那么您肯定不想使用version.service.send 方法。该方法仅在您需要在测试上下文中访问文件时才可行。如果您要避免在运行该部分代码时发生测试错误,那么我建议您存根 open 方法。这有意义吗?
  • 感谢 Carlos,非常有道理。我很惊讶这与 ActiveStorage 如此复杂,这似乎是一个相当普遍和简单的要求。
  • 好主意。完成!
猜你喜欢
  • 1970-01-01
  • 2019-06-29
  • 2020-06-26
  • 2017-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-17
相关资源
最近更新 更多