Rails 7.1 allows attaching file or pathname to has_one_attached
Rails 7.1 allows attaching file or pathname to has_one_attached associations. This feature simplifies passing a file or a pathname in test files when creating model instances.
Active Storage is a built-in Rails feature that provides a unified interface for uploading, storing, and processing files. It supports multiple cloud storage services, such as Amazon S3, Google Cloud Storage, and Microsoft Azure Storage. Active Storage also comes with a local disk-based service for development and testing.
Before Rails 7.1
Before Rails 7.1,
the has_one_attached
association only accepted Active Storage blobs as attachments.
This meant that users had to first upload a file to Active Storage
before they could attach it to a model.
Let's say you have a Rails application with a User
model.
Your application accepts an image when creating a new user.
Your application attaches a default avatar
if the user does not upload any image.
You may want to attach a default avatar from your Rails directory,
as shown:
class User < ApplicationRecord
has_one_attached :avatar_image
end
@user = User.find_by_email("[email protected]")
@user.avatar_image.attach(
io: File.open("path/to/default_avatar_image"),
filename: "avatar_image.png",
content_type: "image/png",
)
You might have to implement the below method in the test or factory class.
FactoryBot.define do
factory :user do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
trait :with_avatar_image do
transient do
avatar_file { Rails.root.join("spec", "fixtures", "avatar_image.png") }
end
after :build do |user, evaluator|
file = evaluator.avatar_file
user.avatar_image.attach(
io: file.open,
filename: file.basename.to_s,
)
end
end
end
end
A developer needs to ensure the image is first uploaded to the ActiveStorage location
and
then it is attached to the User
avatar field.
These steps can be encapsulated,
making the code much easier to understand
and
write.
In Rails 7.1
With the recent changes in Rails 7.1,
you can pass the file
or
pathname to the has_one_attached
association.
class User < ApplicationRecord
has_one_attached :avatar_image
end
@user = User.find_by_email("[email protected]")
@user.update(avatar_image: File.open("path/to/default_avatar_image"))
Attaching the image in the specs file is straightforward.
FactoryBot.define do
factory :user do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
trait :with_avatar_image do
avatar_image { File.open("path/to/default_avatar_image") }
end
end
end
To know more about this feature, please refer to this PR.