Activestorage固定装置附件

jos*_*onc 10 ruby-on-rails rails-activestorage

在铁轨测试中.我有一个只有activestorage的基本模型:

class User < ApplicationRecord
  has_one_attached :avatar
end
Run Code Online (Sandbox Code Playgroud)

我正试图让它成为固定装置,但没有运气(我确实有一个图像):

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

如何通过灯具正确附加头像文件?

Mic*_*ney 19

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

用户有一个附加的“头像”。假设您有这个用户夹具:

# users.yml
fred:
  name: Fred
Run Code Online (Sandbox Code Playgroud)

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

% mkdir test/fixtures/active_storage
Run Code Online (Sandbox Code Playgroud)

现在,您只需将“attachments.yml”和“blobs.yml”放在该目录中。“附件”记录将引用 blob 以及用户:

# active_storage/attachments.yml
freds_picture:
  name: avatar
  record: fred (User)
  blob: freds_picture_blob
Run Code Online (Sandbox Code Playgroud)

# 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
Run Code Online (Sandbox Code Playgroud)

key是这样产生的代码:

ActiveStorage::Blob.generate_unique_secure_token
Run Code Online (Sandbox Code Playgroud)

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

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

tmp/storage/aa/bb/aabbWNGW1VrxZ8Eu4zmyw13A
Run Code Online (Sandbox Code Playgroud)

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

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

md5_checksum = Digest::MD5.file('tmp/storage/aa/bb/aabbWNGW1VrxZ8Eu4zmyw13A').base64digest
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 如上所述,只有当实际文件存在于配置的保存路径下时,该解决方案才完全有效。鉴于“tmp/”路径被认为是短暂的(并且通常被 git 忽略),我找不到任何可靠的方法来确保此类 Active Storage 测试模拟正常工作。 (2认同)
  • 请注意,如果模型“has_many_attached”,则需要在“name:”字段(在attachments.yml中)使用复数名称。 (2认同)

jos*_*onc 17

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

# config/storage.yml

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

david_avatar_blob: <%= ActiveStorage::FixtureSet.blob filename: "david.png", service_name: "test_fixtures" %>
Run Code Online (Sandbox Code Playgroud)


iGi*_*ian 8

假设您对模型用户进行了测试,默认情况下 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 %>
Run Code Online (Sandbox Code Playgroud)

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

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

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

# active_storage_attachments.yml
one:
  name: 'avatar'
  record_type: 'User'
  record_id: 1
  blob_id: 1
Run Code Online (Sandbox Code Playgroud)

# active_storage_blobs.yml
one:
  id: 1
  key: '12345678'
  filename: 'file.png'
  content_type: 'image/png'
  metadata: nil
  byte_size: 2000
  checksum: "123456789012345678901234"
Run Code Online (Sandbox Code Playgroud)

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

# active_storage_attachment.rb
class ActiveStorageAttachment < ApplicationRecord
end
Run Code Online (Sandbox Code Playgroud)

# active_storage_blob.rb
class ActiveStorageBlob < ApplicationRecord
end
Run Code Online (Sandbox Code Playgroud)

然后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
Run Code Online (Sandbox Code Playgroud)

检查文件夹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
Run Code Online (Sandbox Code Playgroud)

我不知道你的回调,但我希望这会给你一些提示.

  • 无需创建自己的模型,因此可以使用原始的ActiveStorage :: Attachment代替ActiveStorageAttachment并将夹具放在active_storage文件夹下 (2认同)

Axe*_*man 6

感谢@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
Run Code Online (Sandbox Code Playgroud)

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

freds_picture:
  name: picture
  record: fred (User)
  blob: freds_picture_blob
Run Code Online (Sandbox Code Playgroud)

test/fixtures/active_storage/blobs.yml

freds_picture_blob: <%= ActiveStorage::Blob.fixture(
  filename: "freds-picture.jpg"
) %>
Run Code Online (Sandbox Code Playgroud)

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

绝对对我有用,加载一个在系统测试中渲染夹具的视图会正确渲染图像。


小智 5

IS04对我只想扩展的唯一答案缺少评论。

一段时间以来,我一直在尝试执行此操作,然后按照iGian的回答为我工作。但是,我的团队审查了我的PR,并问我为什么要引入与ActiveStorage自己的模型(即ActiveStorage::AttachmentActiveStorage::Blob)如此接近的新模型。

然后我想到我要做的就是将灯具从active_storage_attachments.yml移到active_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 %>
Run Code Online (Sandbox Code Playgroud)