Active Storage появился в Rails 5.2 и стал стандартным способом работы с файлами.
rails active_storage:install
rails db:migrate
local:
service: Disk
root: <%= Rails.root.join("storage") %>
amazon:
service: S3
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
region: us-east-1
bucket: your-bucket
class User < ApplicationRecord
has_one_attached :avatar
has_many_attached :documents
end
def update
@user.avatar.attach(params[:avatar])
redirect_to @user
end
<%= image_tag @user.avatar if @user.avatar.attached? %>
Для более сложных сценариев обработки файлов.
gem 'carrierwave'
bundle install
rails generate uploader Avatar
class User < ApplicationRecord
mount_uploader :avatar, AvatarUploader
end
class AvatarUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :thumb do
process resize_to_fit: [100, 100]
end
end
Для больших файлов лучше использовать прямую загрузку в облачное хранилище.
# config/environments/production.rb
config.active_storage.service = :amazon
<%= form.file_field :avatar, direct_upload: true %>
import { DirectUpload } from "@rails/activestorage"
const input = document.querySelector('input[type=file]')
input.addEventListener('change', (event) => {
const file = event.target.files[0]
const upload = new DirectUpload(file, '/rails/active_storage/direct_uploads')
upload.create((error, blob) => {
const hiddenField = document.createElement('input')
hiddenField.setAttribute('type', 'hidden')
hiddenField.setAttribute('value', blob.signed_id)
hiddenField.name = input.name
document.querySelector('form').appendChild(hiddenField)
})
})
class User < ApplicationRecord
validate :acceptable_avatar
def acceptable_avatar
return unless avatar.attached?
unless avatar.byte_size <= 1.megabyte
errors.add(:avatar, "is too big")
end
acceptable_types = ["image/jpeg", "image/png"]
unless acceptable_types.include?(avatar.content_type)
errors.add(:avatar, "must be a JPEG or PNG")
end
end
end
class AvatarUploader < CarrierWave::Uploader::Base
def extension_whitelist
%w(jpg jpeg png)
end
def size_range
0..1.megabytes
end
end
# variant для преобразований
<%= image_tag user.avatar.variant(resize_to_limit: [100, 100]) %>
gem 'image_processing'
test "can upload file" do
visit new_user_path
attach_file('Avatar', Rails.root.join('test/fixtures/files/avatar.png'))
click_button 'Create User'
assert_text 'User was successfully created'
end
test "validates avatar size" do
user = users(:one)
user.avatar.attach(io: File.open('big_image.jpg'), filename: 'big.jpg')
assert_not user.valid?
end
@user.avatar.purge # Удалить файл
@user.avatar.detach # Отсоединить без удаления
@user.remove_avatar! # Удалить файл
Резюмируем: Rails предлагает несколько способов загрузки файлов - от стандартного Active Storage до специализированных гемов вроде CarrierWave. Выбор зависит от сложности требований: Active Storage отлично подходит для большинства задач, в то время как CarrierWave предлагает больше возможностей для кастомной обработки. Всегда валидируйте загружаемые файлы и учитывайте безопасность при работе с пользовательскими загрузками.