Ruby on Rails: Image Uploads Sideways from Mobile - ruby-on-rails

I'm working on a web application that uses CarrierWave and MiniMagick to handle image uploads for account profile pictures. Right now my AvatarUploader class looks like this
class AvatarUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick
# In the uploader:
def auto_orient
manipulate! do |img|
img = img.auto_orient
end
end
# Choose what kind of storage to use for this uploader:
# storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url
ActionController::Base.helpers.asset_path('default_avatar.png')
end
# Process files as they are uploaded:
# process :scale => [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
version :thumb do
process :auto_orient
process :resize_to_fill => [200, 200]
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
# def extension_white_list
# %w(jpg jpeg gif png)
# end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
and the field for handling avatar upload in the form looks like this
.row
- if f.object.avatar.present?
.field
= image_tag f.object.avatar.url
= f.input :avatar, label: f.object.avatar.present? ? 'Replace Avatar' : 'Avatar'
This all works great on the desktop version of my site but when a user uploads a profile pic they take from their mobile phone it gets turned sideways 90 degrees and I can't figure out why. I thought adding the auto_orient code from this question would fix the problem but it did not

credit: #lando2319
exif image rotation issue using carrierwave and rmagick to upload to s3
try changing your auto_orient method to this:
def auto_orient
manipulate! do |img|
img.tap(&:auto_orient!) #try with and without the ! here.
end
end

Figured it out.
process :auto_orient
Needs to be called outside the version: thumb do loop
Full code
# encoding: utf-8
class AvatarUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick
# In the uploader:
def auto_orient
manipulate! do |img|
img.auto_orient
img
end
end
# Choose what kind of storage to use for this uploader:
# storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url
ActionController::Base.helpers.asset_path('default_avatar.png')
end
# Process files as they are uploaded:
# process :scale => [200, 300]
#
# def scale(width, height)
# # do something
# end
process :resize_to_fit => [400, 400]
process :auto_orient
# Create different versions of your uploaded files:
version :thumb do
process :auto_orient
process :resize_to_fit => [200, 200]
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
# def extension_white_list
# %w(jpg jpeg gif png)
# end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end

Related

how to convert gif to jpg "first frame" and upload it using carrierwave

I'm trying to create new version for my image uploader using carrierwave (fog), I was trying to do a condition version to check if it gif to get rid of the animation and convert to jpg but for some reason it didn't work, although the debugging is kinda tough in this.
here is my code
class SourceImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
include CarrierWave::MiniMagick
include CarrierWave::MimeTypes
include CarrierWave::MimetypeFu
# Choose what kind of storage to use for this uploader:
storage :fog
process :set_content_type
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :big_thumb do
process :resize_to_fit => [600, 99999]
end
version :small_thumb do
process :resize_to_fit => [200, 99999]
end
version :first_frame do
process :remove_animation
end
def filename
"#{secure_token}.#{file.extension}" if original_filename.present?
end
protected
def secure_token
var = :"##{mounted_as}_secure_token"
model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.hex(2))
end
# def is_gif?(new_file)
# new_file.content_type.include? 'gif' rescue false
# end
def remove_animation
if content_type == 'image/gif'
manipulate! { |image| image.collapse! }
end
end
I was trying to user is_gif? method as condition version condition but it didn't work.
any suggestions ?
Cheers!

Rails and carrierwave

I have this error trying to upload images to aws bucket.
no implicit conversion of nil into String
I am currently just using an uploading class and an initializer file.
initializers/carrierwave.rb
Carrierwave.configure do |config|
config.storage = :aws
config.aws_bucket = 'larfs'
config.aws_acl = :public_read
config.assets_host = ''
config.aws_authenticated_url_expiration = 60 * 6 * 24 * 365
config.aws_credentials = {
access_key_id: 132abc,
secret_access_key: 123abc
}
end
videouploader class, (used in this instance just for images)
class VideoUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
storage :aws
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url
# # For Rails 3.1+ asset pipeline compatibility:
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded:
# process :scale => [200, 300]
#
# def scale(width, height)
# process r
# end
# Create different versions of your uploaded files:
version :thumb do
# process :scale => [50, 50]
process :resize_to_fill => [90, 90]
end
version :index do
process :resize_to_fill => [200, 200]
end
version :medium do
# process :scale => [150, 170]
process :resize_to_fit => [200, 300]
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
Add in the Gemfile:-
gem 'carrierwave'
gem 'rmagick'
gem 'fog'
gem 'carrierwave_direct'
In initializers/carrierwave.rb:-
CarrierWave.configure do |config|
config.fog_credentials = {
provider: "AWS",
aws_access_key_id: '132abc',
aws_secret_access_key: '123abc'
}
config.fog_directory = 'larfs'
end
In videouploader class:-
class VideoUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
#storage :file
storage :fog
#storage :aws
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url
# # For Rails 3.1+ asset pipeline compatibility:
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded:
# process :scale => [200, 300]
#
# def scale(width, height)
# process r
# end
# Create different versions of your uploaded files:
version :thumb do
# process :scale => [50, 50]
process :resize_to_fill => [90, 90]
end
version :index do
process :resize_to_fill => [200, 200]
end
version :medium do
# process :scale => [150, 170]
process :resize_to_fit => [200, 300]
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
I spent a LOT of time trying to get carrierwave and fog to work together to upload images to AWS.
In the end, it was as simple as moving away from Fog and using the carrierwave-aws gem - https://github.com/sorentwo/carrierwave-aws
Documentation was pretty easy to follow.
Fog was way more than I needed for a simple image upload and carrierwave-aws just worked.
Lots of benefits to switch unless you're beholden to Fog for a specific need.

Rails + Carrierwave: How to change default file naming of image versions (thumb, small, etc)?

I'm upgrading my project from Rails 2 with attachment_fu to Rails 3 with carrierwave. I have an existing database and file directory with images that were uploaded using attachment_fu. Problem is that in attachment_fu, images were uploaded with the image version (thumb, small, medium, etc) appended to the back of the filename (my_image_small.jpg) while in carrierwave, the default is the other way around (small_my_image.jpg). Where in carrierwave would I change this?
here's my FileUploader:
# encoding: utf-8
class FileUploader < CarrierWave::Uploader::Base
#include UploaderFu
# Include RMagick or MiniMagick support:
SMALL_WIDTH = 101
MEDIUM_WIDTH = 223
LARGE_WIDTH = 345
include CarrierWave::RMagick
# include CarrierWave::MiniMagick
# Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
# include Sprockets::Helpers::RailsHelper
# include Sprockets::Helpers::IsolatedHelper
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
#{}"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
"#{Rails.root}/public/file_uploads/#{("%08d" % model.id).scan(/..../).join('/')}"
#{}"#{Rails.root}/public/file_uploads/"
end
version :small do
process :resize_to_fit => [SMALL_WIDTH, 10000]
end
version :medium do
process :resize_to_fit => [MEDIUM_WIDTH, 10000]
end
version :large do
process :resize_to_fit => [LARGE_WIDTH, 10000]
end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url
# # For Rails 3.1+ asset pipeline compatibility:
# # asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded:
# process :scale => [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
# version :thumb do
# process :scale => [50, 50]
# end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
To override the filename convention for a specific version, you can define a full_filename method in the version block:
version :small do
def full_filename(for_file)
[super(for_file), version_name].compact.join('_')
end
process :resize_to_fit => [SMALL_WIDTH, 10000]
end
This method is simply a rewrite of the existing full_filename method in the CarrierWave source code (see versions.rb).
You'll need to override this on every version, however. Instead, you might want to change CarrierWave's default behavior by patching the Versions module. You can add this an an initializer:
module CarrierWave
module Uploader
module Versions
def full_filename(for_file)
[super(for_file), version_name].compact.join('_')
end
end
end
end
Update:
To correct the issue with the file extension, you can use Rake's pathmap function to parse the filename:
require 'rake'
def full_filename(for_file)
filename = for_file.pathmap("%n")
extension = for_file.pathmap("%x")
[filename, version_name].compact.join('_') + extension
end
Just in case anyone wants to know how I figured it out, I looked into the gem code and found out the filename was being set by def full_filename, so in my FileUploader I rewrote the method so that it would overwrite the behavior.
def full_filename (for_file = model.filename.file)
"#{for_file[/(.+)\./][$1]}_#{version_name}.#{for_file[/\.(.+)/][$1]}"
end

how to use CarrierWave def filename

I am using CarrierWave gem to upload images. The problem is, if anyone opens the network terminal in the browser they can easily find out the name of the image. So I just want to avoid it by renaming the image file while deploying to the server. So I can use filename. But the problem is here. The "filename" method is not at all executing in my code. Here is my uploader file.
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded:
# process :scale => [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
version :thumb do
process :resize_to_limit => [100, 100]
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
def filename
logger.info "*******inside filename method"
end
end
Thanks in advance

Default URL not loading with Carrierwave in Rails

I'm having issues setting a default image in my carrierwave uploader. It seems to be appending a weird class to the front of the URL but not rendering the image. See my code below.
Helper
# encoding: utf-8
class UserpicUploader < CarrierWave::Uploader::Base
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
# Include RMagick or MiniMagick support:
include CarrierWave::RMagick
# include CarrierWave::MiniMagick
# Include the Sprokets helpers for Rails 3.1+ asset pipeline compatibility:
# include Sprockets::Helpers::RailsHelper
# include Sprockets::Helpers::IsolatedHelper
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Process files as they are uploaded:
version :normal do
process :resize_to_fill => [162, 163]
end
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url
# For Rails 3.1+ asset pipeline compatibility:
# asset_path("fallback/" + [normal, "profile_default_pic.png"].compact.join('_'))
"/images/fallback/" + [normal, "profile_default_pic.png"].compact.join('_')
end
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
# version :thumb do
# process :scale => [50, 50]
# end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
def filename
if original_filename
#name ||= Digest::MD5.hexdigest(File.dirname(current_path))
"#{#name}.#{file.extension}"
end
end
end
EDIT...
Here is the edited code that worked. I had to put the image in public/fallback instead of Assets/images/fallback.
# encoding: utf-8
class UserpicUploader < CarrierWave::Uploader::Base
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
# Include RMagick or MiniMagick support:
include CarrierWave::RMagick
# include CarrierWave::MiniMagick
# Include the Sprokets helpers for Rails 3.1+ asset pipeline compatibility:
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Process files as they are uploaded:
version :normal do
process :resize_to_fill => [162, 163]
end
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url
# For Rails 3.1+ asset pipeline compatibility:
asset_path("fallback/" + [normal, "profile_default_pic.png"].compact.join('_'))
# "/fallback/" + [normal, "profile_default_pic.png"].compact.join('_')
end
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
# version :thumb do
# process :scale => [50, 50]
# end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
def filename
if original_filename
#name ||= Digest::MD5.hexdigest(File.dirname(current_path))
"#{#name}.#{file.extension}"
end
end
end
Ok I got it working this is what I was missing...
The default folder had to be in the public/ folder not in assets/images
I had to add the following lines to the uploader class:
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
I had to change the default_url to the following:
asset_path("fallback/" + [normal, "profile_default_pic.png"].compact.join('_'))
In Rails 4.1.* you can just specify the filename in the default_url method
def default_url
"default.png"
end
In this case the default.png should be in /app/assets/images folder
edit the uploader class :
def default_url
"/images/fallback/" + [version_name,"default.png"].compact.join('_')
end
and then copy the default picture in /images/fallback/default.png

Resources