Reputation: 131
I try to use Active Storage with Amazon Web Services, instead of Carrierwave and Cloudinary.
With Carrierwave I had some features that allow to resize images before uploading trough an UploaderController.
But how to do that with Active Storage ?
I try this :
Gemfile :
gem 'aws-sdk-s3', require: false
gem 'image_processing', '~> 1.2'
gem 'mini_magick', '~>4.9'
item.rb
class Item < ApplicationRecord
has_one_attached :photo
end
I have a form in my view :
<%= f.input :photo, input_html: { accept: ('image') } %>
I get this object as photo :
#<ActiveStorage::Attached::One:0x00005641d296e1b8 @name="photo", @record=#<Item id: nil, name: "test0941", verbe: "To Lend", collection_id: nil, created_at: nil, updated_at: nil, price_cents: 0, description: "", category_id: 78, photo: nil>, @dependent=:purge_later>
And in my controller :
@item = Item.new(item_params)
@item.photo.combine_options do |b|
b.resize "250x200>"
end
I can't achieve to resize my photo with methods of MiniMagick gem.
Does anybody have any ideas to do that ?
Thanks for your help, Thibault
Upvotes: 10
Views: 6604
Reputation: 167
If params[:item][:photo] is the param from your post you can add
image = MiniMagick::Image.new(params[:item][:photo].tempfile.path)
image.resize "250x200>"
With ImageProcessing::Vips (default in Rails 7)
path = params[:game][:photo].tempfile.path
image = ImageProcessing::Vips.source(path)
result = image.resize_to_limit!(800, 800)
params[:game][:photo].tempfile = result
Upvotes: 10
Reputation: 174
Add this as a private
method to your controller:
def resize_before_save(image_param, width, height)
return unless image_param
begin
ImageProcessing::MiniMagick
.source(image_param)
.resize_to_fit(width, height)
.call(destination: image_param.tempfile.path)
rescue StandardError => _e
# Do nothing. If this is catching, it probably means the
# file type is incorrect, which can be caught later by
# model validations.
end
end
Then call it from a before_action
in the controller.
before_action lambda {
resize_before_save(item_params[:picture], 250, 250)
}, only: [:create, :update]
Upvotes: 3
Reputation: 154
I did it like this:
# config/initializers/activestorage.rb
# Ability to auto apply :default variant (if defined) before uploading original image
Rails.application.config.after_initialize do
ActiveStorage::Blob.class_eval do
alias_method :upload_without_unfurling_orig, :upload_without_unfurling
def upload_without_unfurling(io)
variant = attachments.first.send(:variants)
default_variant = variant[:default]
if default_variant
ActiveStorage::Variation.wrap(default_variant).transform(io) do |output|
unfurl output, identify: identify
upload_without_unfurling_orig(output)
end
else
upload_without_unfurling_orig(io)
end
end
end
end
# user.rb
class User < ApplicationRecord
has_one_attached :photo do |attachable|
attachable.variant :thumb, resize_to_fill: [100, nil]
# This variant will be applied before uploading the original image
attachable.variant :default, strip: true, quality: 70, resize_to_fill: [500, 500]
end
end
# rspec
RSpec.describe User, type: :model do
describe 'when uploading photo' do
it 'applies :default variant before uploading the original image' do
allow(ActiveStorage::Variation).to receive(:wrap).and_call_original
create(:user, :with_photo)
exp_args = hash_including(resize_to_fill: [500, 500])
expect(ActiveStorage::Variation).to have_received(:wrap).with(exp_args)
end
end
end
Upvotes: 1
Reputation: 27
Active storage has a solution for your problem. You don't need to resize images in your controller.You can just use it as item.photo.variant(resize: '100x100') in your view file. Active Storage will create new variant images like magic.
https://edgeguides.rubyonrails.org/active_storage_overview.html
Upvotes: -4