28

在轨道测试中。我有一个只有活动存储的基本模型:

class User < ApplicationRecord
  has_one_attached :avatar
end

我正在尝试使其成为固定装置,但没有运气(我确实有一张图片):

# users.yml
one:
  avatar: <%= File.open Rails.root.join('test', 'files', 'image.png').to_s %>

如何通过固定装置正确附加头像文件?

4

5 回答 5

23

这比任何人想象的要容易得多。我并不是要贬低任何人,因为我花了一些时间才根据这些答案弄清楚这一点。我将使用相同的数据模型来简化它。

用户有一个附加的“头像”。假设你有这个用户装置:

# users.yml
fred:
  name: Fred

这是您需要做的所有事情:

% mkdir test/fixtures/active_storage

现在,您只需将“attachments.yml”和“blob.yml”放在该目录中。“附件”记录将引用 blob 以及用户(注意name条目是has_one_attached字段的名称):

# active_storage/attachments.yml
freds_picture:
  name: avatar
  record: fred (User)
  blob: freds_picture_blob

# active_storage/blobs.yml
freds_picture_blob:
  key: aabbWNGW1VrxZ8Eu4zmyw13A
  filename: fred.jpg
  content_type: image/jpeg
  metadata: '{"identified":true,"analyzed":true}'
  byte_size: 1000
  checksum: fdUivZUf74Y6pjAiemuvlg==
  service_name: local

key代码中生成如下:

ActiveStorage::Blob.generate_unique_secure_token

您可以在控制台中运行它以获取上述夹具的密钥。

现在,这将“起作用”以附上图片。如果您需要实际文件,请首先查看 config/storage.yml 以查看文件存储在哪个路径中。默认情况下,它是“tmp/storage”。上面的文件将存储在这里:

tmp/storage/aa/bb/aabbWNGW1VrxZ8Eu4zmyw13A

要计算校验和,请参见此处:

rails ActiveStorage的blob表中的校验和是如何计算的

md5_checksum = Digest::MD5.file('tmp/storage/aa/bb/aabbWNGW1VrxZ8Eu4zmyw13A').base64digest

可以在夹具中使用 erb 填写文件大小和校验和:

  byte_size: <%= File.size('tmp/storage/aa/bb/aabbWNGW1VrxZ8Eu4zmyw13A') %>
  checksum: <%= Digest::MD5.file('tmp/storage/aa/bb/aabbWNGW1VrxZ8Eu4zmyw13A').base64digest %>

请注意,您必须先将文件复制到存储目录中。测试环境的存储根目录tmp/storage/默认为,其余路径由key(ie tmp/storage/aa/bb)的前四个字符构成。

于 2019-04-24T17:56:43.443 回答
14

假设您对模型用户进行了测试,默认设置UserTest#test_the_truth

rails test test/models/user_test.rb

我想你 Errno::ENOENT: No such file or directory @ rb_sysopen 在测试过程中遇到了错误,因为你的路径有错误,你必须添加'fixtures',它应该是这样的:

# users.yml
one:
  name: 'Jim Kirk'
  avatar: <%= File.open Rails.root.join('test', 'fixtures', 'files', 'image.png').to_s %>

但现在你应该有这个错误:ActiveRecord::Fixture::FixtureError: table "users" has no column named "avatar".

这是正确的,因为 ActiveStorage 使用两个表来工作:active_storage_attachmentsactive_storage_blobs.


因此,您需要从中删除头像列users.yml并添加两个新文件:

免责声明另请参阅下面的评论:“无需创建自己的模型,因此ActiveStorageAttachment您可以使用原始模型ActiveStorage::Attachment并将夹具放置在 active_storage 文件夹下”,另请参阅https://stackoverflow.com/a/55835955/5239030

# active_storage_attachments.yml
one:
  name: 'avatar'
  record_type: 'User'
  record_id: 1
  blob_id: 1

# active_storage_blobs.yml
one:
  id: 1
  key: '12345678'
  filename: 'file.png'
  content_type: 'image/png'
  metadata: nil
  byte_size: 2000
  checksum: "123456789012345678901234"

此外,App/models添加,即使 ActiveStorage 不需要工作

# active_storage_attachment.rb
class ActiveStorageAttachment < ApplicationRecord
end

# active_storage_blob.rb
class ActiveStorageBlob < ApplicationRecord
end

然后就UserTest#test_the_truth成功了。

但最好摆脱 active_storage_attachment.rbactive_storage_blob.rb按照另一种方式进行测试。

要测试附件是否正常工作,请更好地测试控制器,例如将此代码添加到test/controllers/users_controller_test.rb

require 'test_helper'

class UserControllerTest < ActionController::TestCase
  def setup
    @controller = UsersController.new
  end
  test "create user with avatar" do
    user_name = 'fake_name'
    avatar_image = fixture_file_upload(Rails.root.join('test', 'fixtures', 'files', 'avatar.png'),'image/png')
    post :create, params: {user: {name: user_name, avatar: avatar_image}}
  end
end

检查文件夹tmp/storage,应该是空的。

使用以下命令启动测试:rails test test/controllers/users_controller_test.rb

应该会成功,然后如果再次签入tmp/storage,应该会找到一些测试生成的文件夹和文件。

评论后编辑: 如果您需要测试User模型上的回调,那么这应该工作:

# rails test test/models/user_test.rb

require 'test_helper'

class UserTest < ActiveSupport::TestCase
  test "should have avatar attached" do
    u = User.new
    u.name = 'Jim Kirk'
    file = Rails.root.join('test', 'fixtures', 'files', 'image.png')
    u.avatar.attach(io: File.open(file), filename: 'image.png') # attach the avatar, remove this if it is done with the callback
    assert u.valid?
    assert u.avatar.attached? # checks if the avatar is attached
  end
end

我不知道你的回电,但我希望这能给你一些提示。

于 2018-06-03T14:38:12.483 回答
11

IS04 对我只想扩展的唯一答案发表了一条丢失的评论。

一段时间以来,我一直在尝试这样做,并且遵循 iGian 的回答确实对我有用。然而,我的团队审查了我的 PR,并问我为什么要引入与 ActiveStorage 自己的模型(即ActiveStorage::AttachmentActiveStorage::Blob)名称如此接近的新模型。

然后我突然想到,我需要做的就是将固定装置active_storage_attachments.ymlactive_storage/attachments.yml.

我必须通过额外研究弄清楚的另一部分是如何将这些设备与自动生成的 id 一起使用。我这样做是这样使用ActiveRecord::FixtureSet.identify的:

attachment_identifier:
  name: "attachment_name"
  record_type: "MyRecordClass"
  record_id: <%= ActiveRecord::FixtureSet.identify(:my_record_identifier) %>
  blob_id: <%= ActiveRecord::FixtureSet.identify(:blob) %>
  created_at: <%= Time.zone.now %>
于 2018-11-15T23:17:03.750 回答
7

感谢@Alex Ghiculescu 打开 Rails 的 PR,让我知道“Active Storage 的测试套件是如何做到的”。不幸的是,该代码似乎不在 6.1 分支中,但它们有一个ActiveStorage::FixtureSet

同时,您可以将其添加到您的test_helper.rb(或者您想组织代码中:

class ActiveStorage::Blob
  def self.fixture(filename:, **attributes)
    blob = new(
      filename: filename,
      key: generate_unique_secure_token
    )
    io = Rails.root.join("test/fixtures/files/#{filename}").open
    blob.unfurl(io)
    blob.assign_attributes(attributes)
    blob.upload_without_unfurling(io)

    blob.attributes.transform_values { |values| values.is_a?(Hash) ? values.to_json : values }.compact.to_json
  end
end

现在您可以像这样添加您的freds-picture.jpgintotest/fixtures/files和您的夹具文件: test/fixtures/active_storage/attachments.yml

freds_picture:
  name: picture
  record: fred (User)
  blob: freds_picture_blob

test/fixtures/active_storage/blobs.yml

freds_picture_blob: <%= ActiveStorage::Blob.fixture(
  filename: "freds-picture.jpg"
) %>

希望这是有道理的,一旦ActiveStorage::FixtureSet在您的 Rails 版本中,您可以删除该self.fixture方法并在您的夹具 yaml 文件中替换ActiveStorage::Blob.fixture为。ActiveStorage::FixtureSet.blob

绝对对我有用,加载在系统测试中呈现夹具的视图可以正确呈现图像。

于 2021-03-24T16:39:55.357 回答
5

现在(rails 7),根据rails 指南,正确的方法似乎是:

# config/storage.yml

test_fixtures:
  service: Disk
  root: <%= Rails.root.join("tmp/storage_fixtures") %>
# active_storage/users.yml
david:
  name: David
# active_storage/attachments.yml
david_avatar:
  name: avatar
  record: david (User)
  blob: david_avatar_blob
# active_storage/blobs.yml

david_avatar_blob: <%= ActiveStorage::FixtureSet.blob filename: "david.png", service_name: "test_fixtures" %>
于 2021-06-25T02:38:49.163 回答