app/models/user.rb
class User < ApplicationRecord
has_one_attached :avatar
end
app/controllers/admin/home_controller.rb
class Admin::HomeController < Admin::BaseController
def show
end
end
app/views/admin/home/show.html.slim
- if current_user.avatar.attached?
/ - binding.pry
= image_tag current_user.avatar.variant(resize: "160x160"), alt: 'User Image', class: 'img-circle elevation-2'
- else
= image_tag 'backend/default-avatar.png', alt: 'User Image', class: 'img-circle elevation-2'
config/environments/production.rb
config.active_storage.service = :local
config/environments/development.rb
config.active_storage.service = :local
config/storage.yml
local:
service: Disk
root: <%= Rails.root.join("storage") %>
I works in environment: developpment.
But it doesn't work in environment: production
Errno::ENOENT in ActiveStorage::DiskController#show
No such file or directory # rb_file_s_mtime - /apps/example.com/releases/20200129093910/storage/kD/vP/kDvP9igiNZ58NMWhx1zAiKoC
Rails 5.2.4
Used:
https://edgeguides.rubyonrails.org/configuring.html#configuring-active-storage
Active_Storage (Failed to load resource: 500 error) in Production
https://github.com/rails/rails/issues/31581
Rails API ActiveStorage: Get Public URL to display image from AWS S3 Bucket?
mkdir public/storage
config/deploy.rb
set :linked_dirs, %w{tmp/pids tmp/cache tmp/sockets vendor/bundle public/uploads public/storage}
run command
bundle exec cap production linked_files:upload_dirs
Thanks mechnicov.
Related
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
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 rails7)
path = params[:game][:photo].tempfile.path
image = ImageProcessing::Vips.source(path)
result = image.resize_to_limit!(800, 800)
params[:game][:photo].tempfile = result
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
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.
Here is the documentation for active storage.
https://edgeguides.rubyonrails.org/active_storage_overview.html
I'm trying to host my images on s3 but when I deploy my app to heroku it returns me an error:
Heroku log:
Completed 500 Internal Server Error in 14ms
2013-02-18T13:58:01+00:00 app[web.1]:
2013-02-18T13:58:01+00:00 app[web.1]: 12: <%= f.input :needshussler, as: :boolean, label: "Hussler" %>
2013-02-18T13:58:01+00:00 app[web.1]: ActionView::Template::Error (no such file to load -- aws-sdk (You may need to install the aws-sdk gem)):
I have created a bucket in amazon called startupcogs-pro
My config/s3.yml file contains:
development:
bucket: startupcogs-dev
access_key_id: ***
secret_access_key: ***
production:
bucket: startupcogs-pro
access_key_id: ***
secret_access_key: ***
My initializers/s3.rb contains:
if Rails.env == "production"
# set credentials from ENV hash
S3_CREDENTIALS = { :access_key_id => ENV['S3_KEY'], :secret_access_key => ENV['S3_SECRET'], :bucket => ENV['S3_BUCKET']}
else
# get credentials from YML file
S3_CREDENTIALS = Rails.root.join("config/s3.yml")
end
My model has:
has_attached_file :image, :storage => :s3, :s3_credentials => S3_CREDENTIALS, styles: { large: "800x600>"}
And i set my heroku keys this way:
heroku config:add S3_KEY=*** S3_SECRET=*** S3_BUCKET=startupcogs-dev
Any help would be awesome! Struggling for some time now....
Thankyou
Apparently I only had the aws-s3 gem and not the aws-sdk gem as well!
How do I create a file download link in ActiveAdmin to download an uploaded file?
I tried something like this:
action_item :only=> :show do
link_to('Download file', [#user, :upload_file])
end
The action_item will establish the button in the taskbar, but it does not create the actual route or the controller's action method.
You can achieve the download functionality by creating a custom member_action in user.rb
# In app/admin/users.rb
action_item only: [:show] do
link_to('Download File', download_admin_user_path(resource)) if resource.upload_file.present?
end
member_action :download, method: :get do
user = User.find(params[:id])
send_file user.upload_file
end
or, my preference, just leverage the RESTful show action in upload_file.rb
# In app/admin/users.rb
action_item only: [:show] do
# NOTE: remove period from file extension
file_ext = resource.upload_file.file_extension.gsub('.', '')
link_to('Download File', download_admin_upload_file_path(resource.upload_file, format: file_ext)) if resource.upload_file.present?
end
# In app/admin/upload_files.rb
controller do
def show
if params[:format] == 'txt' # example of a known mimetype, e.g. text file
send_data resource.path, type: 'text/plain'
elsif params[:format] == resource.file_extension # example of unknown mimetype
send_file resource.path
# let ActiveAdmin perform default behavior
else
super
end
end
end
cite: http://activeadmin.info/docs/8-custom-actions.html
I don't know the complete code that you are using but that should work -
routes.rb -
resources :users do
collection do
get :upload_file
end
end
controller -
def upload_file
send_file #user.upload_file.path, :type => 'application/pdf', :filename => #user.permalink
end
View -
<%= link_to 'Download file', upload_file_users_path(#user) %>
Everyone: I already searched the error before I posted this to Stackoverflow, so no need to point me to this: groups.google.com/forum/?fromgroups=#!topic/carrierwave/ It's not the same problem.
I'm using Carrierwave so users can upload files to my Rackspace container. But when I Submit from my site (on my local machine, still in test mode), I get a Fog::Storage::Rackspace::NotFound app/controllers/authors_controller.rb:8:in `update' error. My Rackspace container is called kontainer.ofstuff. Here's my code:
pic_uploader.rb:
class PicUploader < CarrierWave::Uploader::Base
include Rails.application.routes.url_helpers
storage :fog
def store_dir
"#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
model author.rb
class Author < ActiveRecord::Base
attr_accessible :stuff, :profilepic
mount_uploader :pic, PicUploader
def dostuff
end
end
carrierwave.rb is in the config/initializers directory
CarrierWave.configure do |config|
config.storage = :fog
config.fog_credentials = {
:provider => 'Rackspace',
:rackspace_username => 'myusername',
:rackspace_api_key => '98765asecretnumber3'
})
config.fog_directory = 'kontainer.ofstuff'
config.fog_host = 'https://34567secretnumberiiiii.ssl.cf2.rackcdn.com'
end
controller authors_controller.rb
class AuthorsController < ApplicationController
def update
#author = Author.find(params[:id])
#booklist = Book.where(:author_id => #author.id)
#line 7
if #author.update_attributes(params[:author])
sign_in #author
redirect_to #author
else
render 'profileinfo'
end
end
end
edit.html.erb:
<%= f.file_field :pic %>
<%= f.submit "Save Author Info" %>
When I had this code 'uploading'/storing to a file, this worked fine. Perhaps f.submit does not work with Carrierwave? If not...where do I find the correct code for submitting?
Any ideas what the trouble is?
I also got this error.
Solved by adding this to uploaded code:
class MyUploader < CarrierWave::Uploader::Base
....
def remove!
begin
super
rescue Fog::Storage::Rackspace::NotFound
end
end
end
I kind of had the same problem, but for me it turned out that I needed to make the container multiple times with the same name but for all the regions. I have no idea why it worked after that, but I guess that's something to try?
Update 11-7-2012
So Carrierwave had some updates since my answer. I was able to get a more stable upload through some trial and error. Here's what I did:
Updated carrierwave gem to 0.7.0
Logged into Rackspace and deleted containers for all the regions.
Added one single container. It doesn't matter which region, whichever is more applicable to you.
Made the container public (Enable CDN)
Copied the Public HTTP CDN link for the container
Updated my /config/initalizers/carrierwave.rb file:
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'Rackspace',
:rackspace_username => '[Your Rackspace Username]',
:rackspace_api_key => '[Your Rackspace API key]'
}
config.fog_directory = '[The name of the container you created]'
if Rails.env.production? || Rails.env.staging?
config.asset_host = '[The Public HTTP CDN url for the container]'
end
end
As a note: I configured my uploader to use storage:fog when the environment is production or staging. Otherwise I use the default local file system.
The main thing to note is that carrierwave changed the config 'fog_host' to 'asset_host.'
For what it's worth: I was having this same problem after migrating from AWS to Rackspace. The error was being thrown because part of updating the file is deleting the old file. In my case, the old file was on S3, not on Rackspace, so carrierwave got upset.
This seemed to be a case of Wait A Few Months & install updated gem. The problem pretty much went away. I also got rid of Rackspace & went to Amazon S3, although I had tried S3 earlier with the same issues. I'm crediting the solution to the updated Carrierwave gem.
I would like to use jpegoptim or optipng to compress the image uploaded by users via Paperclip.
I have a Paperclip model configured as:
has_attached_file :image,
:styles => {:thumb => '50x50>', :preview => '270x270>' },
:url => "/system/:class/:attachment/:id/:basename_:style.:extension",
:path => ":rails_root/public/system/:class/:attachment/:id/:basename_:style.:extension"
Question 1:
Is it possible to compress the original image uploaded by user, then let Paperclip resize it , so there's only one compress process? and how to do it?
Question 2:
I am going to do it via the after_post_process callback, and I could get all the instances of three files from image.queued_for_write and I would like to trigger jpegoptim/optipng by the file extension, but when I use current_format = File.extname(file.path), I get something like: .jpg20120508-7991-cqcpf2. Is there away to get the extension string jpg? or is it safe that I just check if the extension string is contained in that string?
Since there's no other answers, here is how I do it in my project and it seems it's being working ok for several months.
class AttachedImage < ActiveRecord::Base
belongs_to :attachable, :polymorphic => true
validates_attachment_presence :image
validates_attachment_content_type :image, :content_type=>['image/jpeg', 'image/png', 'image/gif']
has_attached_file :image,
:styles => {:thumb => '50x50>', :preview => '270x270>' },
# :processors => [:image_compressor],
:url => "/system/:class/:attachment/:id/:basename_:style.:extension",
:path => ":rails_root/public/system/:class/:attachment/:id/:basename_:style.:extension"
after_post_process :compress
private
def compress
current_format = File.extname(image.queued_for_write[:original].path)
image.queued_for_write.each do |key, file|
reg_jpegoptim = /(jpg|jpeg|jfif)/i
reg_optipng = /(png|bmp|gif|pnm|tiff)/i
logger.info("Processing compression: key: #{key} - file: #{file.path} - ext: #{current_format}")
if current_format =~ reg_jpegoptim
compress_with_jpegoptim(file)
elsif current_format =~ reg_optipng
compress_with_optpng(file)
else
logger.info("File: #{file.path} is not compressed!")
end
end
end
def compress_with_jpegoptim(file)
current_size = File.size(file.path)
Paperclip.run("jpegoptim", "-o --strip-all #{file.path}")
compressed_size = File.size(file.path)
compressed_ratio = (current_size - compressed_size) / current_size.to_f
logger.debug("#{current_size} - #{compressed_size} - #{compressed_ratio}")
logger.debug("JPEG family compressed, compressed: #{ '%.2f' % (compressed_ratio * 100) }%")
end
def compress_with_optpng(file)
current_size = File.size(file.path)
Paperclip.run("optipng", "-o7 --strip=all #{file.path}")
compressed_size = File.size(file.path)
compressed_ratio = (current_size - compressed_size) / current_size.to_f
logger.debug("#{current_size} - #{compressed_size} - #{compressed_ratio}")
logger.debug("PNG family compressed, compressed: #{ '%.2f' % (compressed_ratio * 100) }%")
end
end
There are also some gems to optimize paperclip images:
paperclip-optimizer
paperclip-compressor
Might be a performance compromise but I got images better compressed with FFMPEG or AVCONV.
sudo apt-get install ffmpeg
= initializer
Paperclip.options[:command_path] = "/usr/bin/" # see `which ffmpeg`
= Modal
after_save :compress_with_ffmpeg
def compress_with_ffmpeg
[:thumb, :original, :medium].each do |type|
img_path = self.avtar.path(type)
Paperclip.run("ffmpeg", " -i #{img_path} #{img_path}")
end
end
I got 1.7MB image compressed to 302.9KB!!!