Improve Fixture support for Active Storage (#41065)
* Improve Fixture support for Active Storage
Inspired by [76b33aa][], this commit extends the Active Storage
documentation to elaborate on how to declare fixtures.
In support of that, also introduce the `ActiveStorage::FixtureSet.blob`
method for injecting in-line [ActiveStorage::Blob][] attributes directly
into fixture YAML.
[76b33aa]: 76b33aa3d1
[ActiveStorage::Blob]: https://edgeapi.rubyonrails.org/classes/ActiveStorage/Blob.html
* Extra CR for style
* Two-space indention
* Explaining variable didn't explain, inline for style
Co-authored-by: David Heinemeier Hansson <david@loudthinking.com>
This commit is contained in:
parent
b32823a7ec
commit
c0f33b923b
@ -388,6 +388,10 @@ db_namespace = namespace :db do
|
||||
Dir["#{fixtures_dir}/**/*.yml"].map { |f| f[(fixtures_dir.size + 1)..-5] }
|
||||
end
|
||||
|
||||
if defined? ActiveStorage::FixtureSet
|
||||
ActiveStorage::FixtureSet.file_fixture_path = File.join fixtures_dir, "files"
|
||||
end
|
||||
|
||||
ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files)
|
||||
end
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
* Declare `ActiveStorage::FixtureSet` and `ActiveStorage::FixtureSet.blob` to
|
||||
improve fixture integration
|
||||
|
||||
|
||||
*Sean Doyle*
|
||||
|
||||
Please check [6-1-stable](https://github.com/rails/rails/blob/6-1-stable/activestorage/CHANGELOG.md) for previous changes.
|
||||
|
@ -37,6 +37,7 @@ module ActiveStorage
|
||||
extend ActiveSupport::Autoload
|
||||
|
||||
autoload :Attached
|
||||
autoload :FixtureSet
|
||||
autoload :Service
|
||||
autoload :Previewer
|
||||
autoload :Analyzer
|
||||
|
71
activestorage/lib/active_storage/fixture_set.rb
Normal file
71
activestorage/lib/active_storage/fixture_set.rb
Normal file
@ -0,0 +1,71 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "active_support/testing/file_fixtures"
|
||||
require "active_record/secure_token"
|
||||
|
||||
module ActiveStorage
|
||||
# Fixtures are a way of organizing data that you want to test against; in
|
||||
# short, sample data.
|
||||
#
|
||||
# To learn more about fixtures, read the
|
||||
# {ActiveRecord::FixtureSet}[rdoc-ref:ActiveRecord::FixtureSet] documentation.
|
||||
#
|
||||
# === YAML
|
||||
#
|
||||
# Like other Active Record-backed models,
|
||||
# {ActiveStorage::Attachment}[rdoc-ref:ActiveStorage::Attachment] and
|
||||
# {ActiveStorage::Blob}[rdoc-ref:ActiveStorage::Blob] records inherit from
|
||||
# {ActiveRecord::Base}[rdoc-ref:ActiveRecord::Base] instances and therefore
|
||||
# can be populated by fixtures.
|
||||
#
|
||||
# Consider a hypothetical <tt>Article</tt> model class, its related
|
||||
# fixture data, as well as fixture data for related ActiveStorage::Attachment
|
||||
# and ActiveStorage::Blob records:
|
||||
#
|
||||
# # app/models/article.rb
|
||||
# class Article < ApplicationRecord
|
||||
# has_one_attached :thumbnail
|
||||
# end
|
||||
#
|
||||
# # fixtures/active_storage/blobs.yml
|
||||
# first_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob filename: "first.png" %>
|
||||
#
|
||||
# # fixtures/active_storage/attachments.yml
|
||||
# first_thumbnail_attachment:
|
||||
# name: thumbnail
|
||||
# record: first (Article)
|
||||
# blob: first_thumbnail_blob
|
||||
#
|
||||
# When processed, Active Record will insert database records for each fixture
|
||||
# entry and will ensure the Action Text relationship is intact.
|
||||
class FixtureSet
|
||||
include ActiveSupport::Testing::FileFixtures
|
||||
include ActiveRecord::SecureToken
|
||||
|
||||
# Generate a YAML-encoded representation of an ActiveStorage::Blob
|
||||
# instance's attributes, resolve the file relative to the directory mentioned
|
||||
# by <tt>ActiveSupport::Testing::FileFixtures.file_fixture</tt>, and upload
|
||||
# the file to the Service
|
||||
#
|
||||
# === Examples
|
||||
#
|
||||
# # tests/fixtures/action_text/blobs.yml
|
||||
# second_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob(
|
||||
# filename: "second.svg",
|
||||
# content_type: "image/svg+xml",
|
||||
# ) %>
|
||||
#
|
||||
def self.blob(filename:, **attributes)
|
||||
new.prepare Blob.new(filename: filename, key: generate_unique_secure_token), **attributes
|
||||
end
|
||||
|
||||
def prepare(instance, **attributes)
|
||||
io = file_fixture(instance.filename.to_s).open
|
||||
instance.unfurl(io)
|
||||
instance.assign_attributes(attributes)
|
||||
instance.upload_without_unfurling(io)
|
||||
|
||||
instance.attributes.transform_values { |value| value.is_a?(Hash) ? value.to_json : value }.compact.to_json
|
||||
end
|
||||
end
|
||||
end
|
41
activestorage/test/fixture_set_test.rb
Normal file
41
activestorage/test/fixture_set_test.rb
Normal file
@ -0,0 +1,41 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
require "database/setup"
|
||||
|
||||
class ActiveStorage::FixtureSetTest < ActiveSupport::TestCase
|
||||
self.fixture_path = File.expand_path("fixtures", __dir__)
|
||||
self.use_transactional_tests = true
|
||||
|
||||
fixtures :all
|
||||
|
||||
def test_active_storage_blob
|
||||
user = users(:first)
|
||||
|
||||
avatar = user.avatar
|
||||
|
||||
assert_equal avatar.blob.content_type, "image/jpeg+override"
|
||||
assert_equal avatar.blob.filename.to_s, "racecar.jpg"
|
||||
assert_equal avatar.blob.service.name, :local
|
||||
avatar.blob.open { |file| assert FileUtils.identical?(file, file_fixture("racecar.jpg")) }
|
||||
end
|
||||
|
||||
def test_active_storage_attachment
|
||||
user = users(:first)
|
||||
|
||||
avatar = user.avatar
|
||||
|
||||
assert_not_predicate avatar, :blank?
|
||||
assert_predicate avatar, :attached?
|
||||
assert_predicate avatar.attachment, :present?
|
||||
end
|
||||
|
||||
def test_active_storage_metadata
|
||||
user = users(:first)
|
||||
|
||||
avatar = user.avatar.tap(&:analyze)
|
||||
|
||||
assert avatar.metadata["identified"]
|
||||
assert avatar.metadata["analyzed"]
|
||||
end
|
||||
end
|
4
activestorage/test/fixtures/active_storage/attachments.yml
vendored
Normal file
4
activestorage/test/fixtures/active_storage/attachments.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
first_avatar_attachment:
|
||||
name: avatar
|
||||
record: first (User)
|
||||
blob: first_avatar_blob
|
4
activestorage/test/fixtures/active_storage/blobs.yml
vendored
Normal file
4
activestorage/test/fixtures/active_storage/blobs.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
first_avatar_blob: <%= ActiveStorage::FixtureSet.blob(
|
||||
filename: "racecar.jpg",
|
||||
content_type: "image/jpeg+override"
|
||||
) %>
|
2
activestorage/test/fixtures/users.yml
vendored
Normal file
2
activestorage/test/fixtures/users.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
first:
|
||||
name: $LABEL
|
@ -43,9 +43,10 @@
|
||||
|
||||
ActiveStorage.logger = ActiveSupport::Logger.new(nil)
|
||||
ActiveStorage.verifier = ActiveSupport::MessageVerifier.new("Testing")
|
||||
ActiveStorage::FixtureSet.file_fixture_path = File.expand_path("fixtures/files", __dir__)
|
||||
|
||||
class ActiveSupport::TestCase
|
||||
self.file_fixture_path = File.expand_path("fixtures/files", __dir__)
|
||||
self.file_fixture_path = ActiveStorage::FixtureSet.file_fixture_path
|
||||
|
||||
include ActiveRecord::TestFixtures
|
||||
|
||||
|
@ -648,6 +648,49 @@ Notice the `category` key of the `first` article found in `fixtures/articles.yml
|
||||
|
||||
NOTE: For associations to reference one another by name, you can use the fixture name instead of specifying the `id:` attribute on the associated fixtures. Rails will auto assign a primary key to be consistent between runs. For more information on this association behavior please read the [Fixtures API documentation](https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html).
|
||||
|
||||
#### File attachment fixtures
|
||||
|
||||
Like other Active Record-backed models, Active Storage attachment records
|
||||
inherit from ActiveRecord::Base instances and can therefore be populated by
|
||||
fixtures.
|
||||
|
||||
Consider an `Article` model that has an associated image as a `thumbnail`
|
||||
attachment, along with fixture data YAML:
|
||||
|
||||
```ruby
|
||||
class Article
|
||||
has_one_attached :thumbnail
|
||||
end
|
||||
```
|
||||
|
||||
```yaml
|
||||
# fixtures/articles.yml
|
||||
first:
|
||||
title: An Article
|
||||
```
|
||||
|
||||
Assuming that there is an [image/png][] encoded file at
|
||||
`test/fixtures/files/first.png`, the following YAML fixture entries will
|
||||
generate the related `ActiveStorage::Blob` and `ActiveStorage::Attachment`
|
||||
records:
|
||||
|
||||
```yaml
|
||||
# fixtures/active_storage/blobs.yml
|
||||
first_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob(
|
||||
filename: "first.png",
|
||||
) %>
|
||||
```
|
||||
|
||||
```yaml
|
||||
# fixtures/active_storage/attachments.yml
|
||||
first_thumbnail_attachment:
|
||||
name: thumbnail
|
||||
record: first (Article)
|
||||
blob: first_thumbnail_blob
|
||||
```
|
||||
|
||||
[image/png]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types
|
||||
|
||||
#### ERB'in It Up
|
||||
|
||||
ERB allows you to embed Ruby code within templates. The YAML fixture format is pre-processed with ERB when Rails loads fixtures. This allows you to use Ruby to help you generate some sample data. For example, the following code generates a thousand users:
|
||||
|
@ -31,6 +31,10 @@
|
||||
ActiveSupport.on_load(:action_dispatch_integration_test) do
|
||||
self.fixture_path = ActiveSupport::TestCase.fixture_path
|
||||
end
|
||||
|
||||
ActiveSupport.on_load(:active_storage_record) do
|
||||
ActiveStorage::FixtureSet.file_fixture_path = ActiveSupport::TestCase.file_fixture_path
|
||||
end
|
||||
end
|
||||
|
||||
# :enddoc:
|
||||
|
Loading…
Reference in New Issue
Block a user