I am currently using carrierwave, and i am wondering if the following his possible. If so how!. Thanks in advance
I have a user and wants to upload an avatar then the following folder would be created
public/image/avatar/customer.id/image01/small
public/image/avatar/customer.id/image01/normal
public/image/avatar/customer.id/image01/big
public/image/avatar/customer.id/image02/small
public/image/avatar/customer.id/image02/normal
public/image/avatar/customer.id/image02/big
Basically, I do not want to overide the previous image has i want to keep them, but create a folder for the newest picture to have it there. Also want the customer id has a path.
Thanks.
PS: if its possible, please provide a tutorial or somesort, if not possible would paperclip allow it? Thanks i can't seem to find anything about it.
uploaders/image_uploader.rb
class ImageUploader < 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
# 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
"public/image/avatar/#{current_user.id}"
end
version :small do
end
version :normal do
end
version :big do
end
end
Your image uploader should look something like that.
Related
I've introduced a new version on my Carrierwave Uploader. When I create a new Event it creates both versions correctly. But when I update it, only the file I attached gets uploaded, but versions do not get recreated.
I am using CarrierWave 1.2.2, and looking at the changelog, it doesn't seem to have been a bug that got fixed in the newer versions
class CoverUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
if Rails.env.development? || Rails.env.test?
storage :file
elsif Rails.env.production?
storage :fog
end
# 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
if ENV['HEROKU_APP_NAME'].to_s.include?('-pr-')
"review_apps/#{model.class.to_s.underscore}/#{model.id}"
else
"#{Rails.env}/#{model.class.to_s.underscore}/#{model.id}"
end
end
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url(*args)
ActionController::Base.helpers.asset_path('test.jpg')
end
# Create different versions of your uploaded files:
version :optimised do
process convert: 'webp'
process :set_content_type_to_webp
def full_filename(_for_file = model.cover.file)
"cover_#{model.id}.webp"
end
def exists?
file&.exists?
end
end
def extension_blacklist
%w(webp)
end
private
# Required to actually force Amazon S3 to treat it like an image
def set_content_type_to_webp
file.instance_variable_set(:#content_type, 'image/webp')
end
end
#ogelacinyc was partly correct when he found the bug in full_filename. I went back to test normal functionality with creating another version, with a simple dimension change. I could then see that update would recreate the versions by itself, just like I expected.
That made me think that maybe there is something wrong with my version :optimised block. So after commenting one by one, I found that full_filename was the culprit. It could have been model.cover.file failing silently, but I think it was model.id, as can be seen in the description for filename method in Carrierwave
So instead, I grab the filename directly, extract extension and substitute it with webp:
def full_filename(for_file = model.file_name.file)
extension = File.extname(for_file)
"cover_#{for_file.sub(extension, '.webp')}"
end
Which works without problems!
You need to add an after_save callback to Event and then call recreate_versions! on your mounted uploader.
Assuming you have an Event model with the following, this would solve your problem.
class Event < ApplicationRecord
mount_uploader :cover_image, CoverUploader
after_save :recreate_versions!
delegate :recreate_versions!, to: :cover_image, allow_nil: true
end
See CarrierWave's README also.
I have been struggling to find any tutorial or question that explains how to upload image and resize it according to certain conditions provided by user.
I am easily able to upload and resize image using hard coded values, however I am stuck at using user provided parameters to be accessed from the Uploader.
I want the image to be resized to either 800x600 or 300x300 based on whether the user checks the image as Large or Small.
For that I have a boolean column named "large" in the model structure.
In the Uploader I am able to access model and its values easily in the store_dir block, but anywhere outside this block any model attribute returns as nil.
This is what I want to do:-
class BannerUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
resize_to_fit(800,600) if model.large==true
resize_to_fit(300,300) if model.large!=true
end
However this returns the error
undefined local variable or method `model' for BannerUploader:Class
How to go about this issue.
To process an original file you can specify custom method:
class BannerUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
process :process_original_version
def process_original_version
if model.large
resize_to_fit(800,600)
else
resize_to_fit(300,300)
end
end
end
For a specific version:
class BannerUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :normal do
if model.large
process resize_to_fit: [800,600]
else
process resize_to_fit: [300,300]
end
end
end
Ok so #Alex Kojin has the right answer. However I was faced with another problem as well. When the user submitted the form, the image would be resized always as small (300x300) because for some reason the image resize process would be executed first and then the "large" attribute would be set as true. Therefore the Uploader would always get model.large as false.
So this is how I had to change my action controller
def create
#banner=Banner.new
#banner.large=params[:large]
#banner.update_attributes(banner_params)
#banner.save
redirect_to :back
end
Not sure if this is the right approach but does work for me.
i am trying to migrate images from local file system to dropbox, so i am using carrierwave dropbox gem to move all images to dropbox. i am able to store new images which is uploaded from my application. I am trying to move the existing images.
i am using Article.first.avatar? method to check whether the image exists or not, i have used this method in many places for different sizes of images in my application.
when i use the above method to find out whether the image exists or not, it says true always when the image is not present in dropbox. Look at my console output(2),
My uploader:
class Avatar < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage: file
def store_dir
if model
"uploads/#{model.class.to_s.underscore}/#{model.id}/#{mounted_as}"
else
"uploads/#{mounted_as}/"
end
end
end
console output (1)
>Article.first.avatar?
>false
#<AvatarUploader:0x007f9813f1fe70
#file=
#<CarrierWave::SanitizedFile:0x007f9813f1e688
#content_type=nil,
#file="/Users/work/project/app1/public/uploads/370/avatar/avatar.png",
#original_filename=nil>,
#model=
##Article model
#mounted_as=:avatar,
#storage=#<CarrierWave::Storage::File:0x007f9813f1fad8 #uploader=#<AvatarUploader:0x007f9813f1fe70 ...>>,
#versions={}>
I changed uploader as follows:
class Avatar < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage: dropbox
def store_dir
if model
"uploads/#{model.class.to_s.underscore}/#{model.id}/#{mounted_as}"
else
"uploads/#{mounted_as}/"
end
end
end
console output(2)
>Article.first.avatar?
>true
#<AvatarUploader:0x007f8574143ee8
#file=
#<CarrierWave::Storage::Dropbox::File:0x007f8574143308
#client=
#<DropboxClient:0x007f8574143420
#root="dropbox",
#session=
#<DropboxSession:0x007f8574143498
#access_token=#<OAuthToken:0x007f8574143470 #key="123453333", #secret="22222222222">,
#consumer_key="abcdeafs",
#consumer_secret="asdfasfj",
#locale=nil,
#request_token=nil>>,
#config=
{:app_key=>"asdfasfasf",
:app_secret=>"asdfkasfksf",
:access_token=>"adfkjasfkhs",
:access_token_secret=>"aksdfkhsfksf",
:access_type=>"dropbox",
:user_id=>"292929292"},
#path="uploads/images/370/avatar.png",
#uploader=#<AvatarUploader:0x007f8574143ee8 ...>>,
#model=
#Artcle Model>,
#mounted_as=:image,
#storage=
#<CarrierWave::Storage::Dropbox:0x007f8574143c90
#config=
{:app_key=>"asdfasfasf",
:app_secret=>"asdfkasfksf",
:access_token=>"adfkjasfkhs",
:access_token_secret=>"aksdfkhsfksf",
:access_type=>"dropbox",
:user_id=>"292929292"},
#dropbox_client=
#<DropboxClient:0x007f8574143420
#root="dropbox",
#session=
why does it show "true" when the image is not present.
how can i get "false" when the image is not present in dropbox.
My stab in the dark is that inside Carrierwave, the normal file class it returns (sanitized file) responds to empty by checking if the file exists:
https://github.com/carrierwaveuploader/carrierwave/blob/master/lib/carrierwave/sanitized_file.rb#L144
Inside the carrierwave dropbox gem, the File class (https://github.com/robin850/carrierwave-dropbox/blob/master/lib/carrierwave/storage/dropbox.rb#L45) doesn't implement this. I'm guessing if you reopened the class and added
module CarrierWave
module Storage
class Dropbox < Abstract
class File
def empty?
# use dropbox API to get the file and check the presence here
end
end
end
end
end
It would probably work?
We are using carrierwave gem to upload our images on a rails project.
We need to support the creation of the object without an image, but the application will run on several platforms and we don't want to support objects without images in everyone o that platforms, so we want to have a default image.
So this was the first solution
class IconUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
def store_dir
"uploads/#{model.id}"
end
def default_url
"/images/icons/" + [version_name, "default.png"].compact.join('_')
end
version :thumbnail do
process resize_to_fill: [200, 200]
end
version :high_resolution do
process resize_to_fill: [400, 400]
end
end
The problem with this is that all the devices will come to the server (not to S3) looking for that default image.
At the same time its a problem with the multiple versions of the image.
So this second solution came:
class CategoryController < ApplicationController
...
def create
#category = Category.new(category_params)
#uploader = IconUploader.new(#category, :icon)
uploader.cache!(File.open("app/assets/images/photos/picture.jpg"))
#category.image=#uploader
#object.save
end
...
end
This solves the problem of the multiple resolutions and it always goes to S3 to get the image. But the problem here is that it will duplicate the default image on S3 many times.
Our third solution could be a to use an already created image on Amazon as default URL, but it has the same problem with the version so we don't even implement it.
Can any one think of a better solution for this problem?
I watched Railscast 253 and decided to use Carrierwave for my file uploading needs. I know I must be doing something very dumb, but I am neither successful in overriding the store_dir method nor the filename method in my uploader. The following is my code which nearly identical to Ryan Bates' code in the Railscast.
class DocumentUploader < CarrierWave::Uploader::Base
# some stuff here
# 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
"documents/#{model.class.to_s.underscore}/#{model.id}"
end
# more stuff here
def filename
"#{active_customer.last_name}_#{active_customer.first_name}_#{active_system.desc}.pdf" if original_filename
end
end
The uploaded files are instead being stored in public/uploads/tmp with some default file name. What could I be doing wrong here? Is there an important step in the Carrierwave set up that maybe Ryan Bates did not include in the Railscast?