I'm using carrierwave (0.10.0) with Fog for S3 uploads.
Implementing simple uploader:
class AvatarUploader < CarrierWave::Uploader::Base
def default_url(*_args)
"#{Rails.configuration.cdn_url}/no-image.png"
end
def extension_white_list
%w(jpg jpeg gif png)
end
end
and mount it here
class User
include Mongoid::Document
field :name, type: String
mount_uploader :avatar, AvatarUploader
end
When Im trying to set remote image even if no image is presented it doesn't fallback to default_url and simulates generation of file in S3 which is actually not there.
Example:
u = User.find('1234567')
u.remote_avatar_url = 'http://non-existing-url.com/avatar.jpg'
u.save!
And when I access after reloading document
u.reload
u.avatar.url # output https://ourcdn.url/somebucket/avatar.jpg
But when access it in the browser it's showing 404.
Any ideas?
Related
I am using CarrierWave + rmagick gems to upload image to server. When I am uploading a normal file, everything goes fine. But when I upload malformed file, the form error doesn't display CarrierWave error, it displays the error which appears when running rmagick.
A simple example. I have User model, and an uploader inside it like that:
class User < ActiveRecord::Base
...
mount_uploader :avatar, PictureUploader
end
(the avatar is a stringfield)
Now, the uploader is defined here:
class BaseImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
storage :fog
def extension_white_list
%w(jpg jpeg gif png)
end
end
class PictureUploader < BaseImageUploader
def default_url
'placeholder.png'
end
def store_dir
'images/pictures'
end
version :thumb do
process resize_to_fit: [50, 50]
end
version :medium do
process resize_to_fill: [400, 400]
end
version :small_square do
process resize_to_fill: [200, 200]
end
end
Then I create an empty file, for example, with touch ~/Desktop/file.jpg, and trying to upload it via the form, and here I am getting a validation error:
Avatar Failed to manipulate with rmagick, maybe it is not an image? Original Error: Empty input file `<foldername>/public/uploads/tmp/1470905765-10111-5893/thumb_file.jpg' # error/jpeg.c/JPEGErrorHandler/322
I tried using ming_magick instead of rmagick, but the result is the same (with slightly different error message)
Can I do something to alter this validation message to say something like Avatar Your image is invalid instead of the default?
Hm, actually that was pretty easy: I just needed to add a string to i18n, like that:
errors.messaging.rmagick_processing_error: "Error processing image"
I have the client upload an image directly to S3 with javascript and have designed the url to be exactly what it would be if carrierwave was uploading it (by using a unique_id that I pass to the create method). Once the image is uploaded, I want to send an AJAX request to create the record, and then process the image using carrierwave, but I don't need carrierwave to handle the upload, just process the versions.
I have this typical carrierwave setup using the fog gem for s3 storage:
class Picture < ActiveRecord::Base
mount_uploader :image, ImageUploader
# . . .
end
and this:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
storage :fog
def store_dir
"uploads/picture/#{model.unique_id}"
end
version :large do
resize_to_limit(600, 600)
end
# . . .
end
But I can't figure out how to create a new Picture without carrierwave wanting to handle the upload.
I have tried setting Picture.image to the filename but it becomes nil:
>> Picture.create(image: params[:filename], unique_id: params[:unique_id])
=> #<Picture id: 96, image: nil, ... >
I have also tried getting the image by using carrierwave's "Uploading files from a remote location" feature:
class PicturesController < ApplicationController
def create
#picture = Picture.create(
remote_image_url: params[:url],
unique_id: params[:unique_id]
)
# . . .
end
# . . .
end
That works eventually, but it is a lot of extra downloading and uploading and feels wrong.
How do I create the Picture without carrierwave getting involved, and then have carrierwave process the image versions?
I have a brand model
class Brand < ActiveRecord::Base
attr_accessible :activities, :attendees, :date, :description, :name, :place, :requirements_on_event, :requirements_other, :requirements_post_event, :requirements_pre_event, :target_students, :target_universities, :type, :image
mount_uploader :image, ImageUploader
end
I have the following in my brands table
t.string "image"
and here is my image_uploader.rb
# encoding: utf-8
class ImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::MiniMagick
include CarrierWave::RMagick
# include ::CarrierWave::Backgrounder::Delay
# Choose what kind of storage to use for this uploader:
storage :file
#storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_white_list
%w(jpg jpeg gif png)
end
end
I have these in my gemfile
#Picture Upload and Storage
gem 'carrierwave'
gem 'carrierwave_backgrounder'
gem 'fog'
#gem 'aws-s3'
gem 'rmagick'
gem 'mini_magick
Now the problem is per the doc on carrierwave's github page
I try
bundle exec rails c and rails c
uploader = ImageUploader.new
I am getting this returned message in green
=> #<ImageUploader:0x007fcf2450bf68 #model=nil, #mounted_as=nil>
why is the #model=nil and #mounted_as=nil?
when I try to this
uploader.store!(/Users/judyngai/Desktop/brandspictures/circle_accupass.png)
I am getting this error
SyntaxError: (eval):2: unknown regexp options - jdyga
and if I try this
uploader.store!('/Users/judyngai/Desktop/brandspictures/circle_accupass.png')
carrierwave won't let me do it
CarrierWave::FormNotMultipart: You tried to assign a String or a Pathname to an uploader, for security reasons, this is not allowed.
I feel like I installed everything correctly. Its a rails 3.2.13 app. I commented out my carrierwave.rb because I am having trouble with fog and aws.
I just tried adding this to my model but still getting the same thing.
require 'carrierwave/orm/activerecord'
You should be calling store! method as below:
uploader.store!(File.open('/Users/judyngai/Desktop/brandspictures/circle_accupass.png'))
You should be passing an instance of File rather than a String. Hence, the error You tried to assign a String or a Pathname to an uploader, for security reasons, this is not allowed.
I am using carrierwave_backgrounder to upload images to S3 in a background process with Sidekiq.
Here's my background_uploader.rb class...
class BackgroundUploader < CarrierWave::Uploader::Base
include ::CarrierWave::Backgrounder::Delay
include CarrierWave::RMagick
include CarrierWave::MimeTypes
process :set_content_type
# Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
storage :fog
def store_dir
"uploads/backgrounds/#{model.id}"
end
def default_url
"/assets/default.jpg"
end
process :resize_to_fit => [1024, 1024]
process :convert => 'jpg'
process :fix_exif_rotation
def extension_white_list
%w(jpg jpeg png)
end
def filename
#name ||= Digest::MD5.hexdigest(File.dirname(current_path.to_s))
"#{#name}.#{file.extension}" if original_filename
end
# Rotates the image based on the EXIF Orientation & applies gaussian blur
def fix_exif_rotation
manipulate! do |img|
img.auto_orient!
img = yield(img) if block_given?
img = img.gaussian_blur(0.0, 20.0)
img
end
end
end
carrierwave_backgrounder.rb:
CarrierWave::Backgrounder.configure do |c|
c.backend :sidekiq, queue: :carrierwave
end
background.rb contains:
mount_uploader :image, BackgroundUploader
process_in_background :image
I then run sidekiq -q carrierwave to fire up the background workers. All is working good! Upload a file, I see the queue accept it and start working...
If I immediately open up my AWS S3 Console I see the original file in there. Non-resized and un-blurred. Once the job is complete...I refresh S3 and there's the resized/blurred version. Now both images are in there, but I only want the blurred image to be there. In my view I use...
<%= image_tag(#background.image.to_s) %>
It displays the original file. If I check the checkbox to remove the file, it does so as it should (deletes the original from S3), but the blurred version stays there.
What's getting uploaded to S3...
original.jpg (immediate...I don't want this uploaded at all)
modified.jpg (after job completes)
Long story short: I don't want the original file to upload to S3.
I think your problem is the filename method, which carrierwave may rely on to find (and delete) the original file. Does the problem go away when you use a filename that doesn't change between when it's initially stored and when you process it?
I've got a photo upload feature in my rails app. The app uploads direct to s3 through carrierwave via rmagick and fog. The issue I am having is when a photo is uploaded via mobile through the "take a photo option" in portrait (note this is with iphone but I believe android has the same issue). Once uploaded the image appears fine on mobile, however when viewed on desktop the image appears rotated 90 degrees.
Through my research it looks to be an issue with exif. This stackoverflow responder outlines 2 potential solutions. This gist also looks promising as well.
So far I have found a few solutions posted but none have worked. Ideally I would like the photo to be saved to s3 as a portrait, then just display the image as is.
Any suggestions are well appreciated.
Below is my code
app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWaveDirect::Uploader
include CarrierWave::RMagick
# Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
include CarrierWave::MimeTypes
process :fix_exif_rotation
process :set_content_type
version :thumb do
process resize_to_fill: [200, 200]
end
def extension_white_list
%w(jpg jpeg png)
end
def fix_exif_rotation #this is my attempted solution
manipulate! do |img|
img = img.auto_orient!
end
end
end
app/models/s3_image.rb
class S3Image < ActiveRecord::Base
attr_accessible :image, :name, :user_id
mount_uploader :image, ImageUploader
belongs_to :user
def image_name
File.basename(image.path || image.filename) if image
end
class ImageWorker
include Sidekiq::Worker
def perform(id, key)
s3_image = S3Image.find(id)
s3_image.key = key
s3_image.remote_image_url = s3_image.image.direct_fog_url(with_path: true)
s3_image.save!
s3_image.update_column(:image_processed, true)
end
end
end
config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.fog_credentials = {
provider: "AWS",
aws_access_key_id: " ... ",
aws_secret_access_key: " ... "
}
config.fog_directory = " ... "
end
btw I used this Railscast as a guide for setting up my s3 upload.
Well I got this working using fog instead or carrierwave_direct.
Below is the code that ended up working for me:
app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
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
def fix_exif_rotation #this is my attempted solution
manipulate! do |img|
img.tap(&:auto_orient)
end
end
process :fix_exif_rotation
end
app/models/s3_image.rb
class S3Image < ActiveRecord::Base
attr_accessible :image, :name, :user_id, :image_cache
mount_uploader :image, ImageUploader
belongs_to :user
end
initializers/carrierwave.rb
CarrierWave.configure do |config|
config.fog_credentials = {
provider: "AWS",
aws_access_key_id: " ... ",
aws_secret_access_key: " ... ",
region: 'us-west-2'
}
config.fog_directory = " ... "
end
I had a similar problem and fixed it with an approach nearly identical to yours.
# In the uploader:
def auto_orient
manipulate! do |img|
img = img.auto_orient
end
end
(Note that I am not calling auto_orient! - just auto_orient, without the bang.)
Then I have process :auto_orient as the first line of any version I create. For example:
version :square do
process :auto_orient
process :resize_to_fill => [600, 600]
end
My solution (quite similar to Sumeet) :
# painting_uploader.rb
process :right_orientation
def right_orientation
manipulate! do |img|
img.auto_orient
img
end
end
It's really important to return an image. Otherwise, you'll get an
NoMethodError (undefined method `write' for "":String):
Lando2319's answer was not working for me.
I am using RMagick.
I managed to make ImageMagick apply the correct orientation (and to reset the EXIF rotation data in order to avoid a double rotation by the viewer) by using :
def fix_exif_rotation # put this before any other process in the Carrierwave uploader
manipulate! do |img|
img.tap(&:auto_orient!)
end
The difference between my solution & Lando's is the bang (!). In my case it was absolutely necessary.