I am having uploading problem using carrierwave and cloudinary on heroku platform in production. Specifically in conditional versioning. Uploading occurs seamlessly to cloudinary, but in generation the version the error occurs.
See my very simple uploader class bellow:
class MediaAlbumUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
if Rails.env.production?
include Cloudinary::CarrierWave
# storage :fog
else
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
version :thumb, if: :image? do
process resize_and_pad: [450, 300]
end
def extension_whitelist
%w(jpg jpeg gif png)
end
protected
def image?(new_file)
new_file.content_type.start_with? 'image'
end
end
In the verification image? the param new_file is nil, look the error:
NoMethodError (undefined method `content_type' for nil:NilClass)
The has extract with heroku logs -t
Remember, uploading to cloudinary occurs without problems so the new_file should not be null.
Related
I am using FOG with Paperclip. I added the following code to give dynamic directory name.
fog_directory: proc { |file| file.instance.repo.name }
It creates the fog directory correctly but when i try to get url it added the local system path with amazon url.
https://s3.amazonaws.com/%23%3CProc:0x4ae8f3bb#/home/apple/projects/project.name/config/initializers/paperclip.rb:8%3E/abc.jpg
I solved it this way by overriding the Paperclip module.
module Paperclip
module Storage
module Fog
def host_name_for_directory
if directory_name.to_s =~ Fog::AWS_BUCKET_SUBDOMAIN_RESTRICTON_REGEX
"#{directory_name}.s3.amazonaws.com"
else
"s3.amazonaws.com/#{directory_name}"
end
end
def directory
#directory ||= connection.directories.new(key: directory_name)
end
def directory_name
if #options[:fog_directory].respond_to?(:call)
#options[:fog_directory].call(self)
else
#options[:fog_directory]
end
end
end
end
end
Using Rails 3.2.12 and Ruby 1.9.2
I simply want to use carrierwave/minimagick as so:
In my Gemfile
gem 'carrierwave'
gem 'mini_magick'
In my uploader
require 'carrierwave/processing/mini_magick'
class AvatarUploader < CarrierWave::Uploader::Base
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:
# 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('_'))
end
process :resize_to_fit => [800, 800]
version :thumb do
process :resize_to_fit => [200,200]
end
version :mini do
process :resize_to_fit => [50,50]
end
version :medium do
process :resize_to_fit => [250,250]
end
def extension_white_list
%w(jpg jpeg gif png)
end
end
The problem is that the thumb, mini and medium versions are saving itself properly but not resizing (the size is the same for all versions).
anyone experiencing something similar?
Ok just figured it out.... after 4 hours of debugging!
I was using ruby 1.9.2 that was not compatible with the resizing of minimagick
Once I upgraded to ruby 1.9.3 everything went back to normal and resizing worked perfectly.
This should be clearly documented.
The website I am working on is going through a redesign and as such, our user images need to be re-sized. The website is currently using carrierwave gem to handle all image and video processing, and each image has a original file with a unique file name based on the following:
def filename
if original_filename
if model && model.read_attribute(:user_image).present?
model.read_attribute(:user_image)
else
#name ||= "#{secure_token}.#{file.extension}" if original_filename.present?
end
end
end
and secure_token be generated by
def secure_token
var = :"##{mounted_as}_secure_token"
model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
end
The task that is created to do this is:
##
# CarrierWave Amazon S3 File Reprocessor Rake Task
#
# Written (specifically) for:
# - CarrierWave
# - Ruby on Rails 3
# - Amazon S3
#
# Works with:
# - Any server of which you have write-permissions in the Rails.root/tmp directory
# - Works with Heroku
#
# Not tested with, but might work with:
# - Ruby on Rails 2
#
# Might work with, after a couple of tweaks:
# - File System Storage
# - Cloud Files Storage
# - GridFS
#
# Examples:
#
# Reprocess all versions of User#avatar
# rake carrierwave:reprocess class=User mounted_uploader=avatar
#
# Reprocess the versions: thumb, small, medium for User#avatar
# rake carrierwave:reprocess class=User mounted_uploader=avatar versions='thumb, small, medium'
#
# Reprocess for an underlying association, for things like Embedded MongoDB Documents
# which are models you cannot access directly, but rather through a regular Document
#
# Embeds One (picture) Association
# rake carrierwave:reprocess class=User association=picture mounted_uploader=image versions='thumb, small, medium'
#
# Embeds Many (pictures) Association
# rake carrierwave:reprocess class=User association=pictures mounted_uploader=image versions='thumb, small, medium'
#
# WARNING
# There is an issue with "Rake", that you cannot name your mounted_uploader "file".
# If you do this, then you will not be able to reprocess images through this rake task
# class User
# include Mongoid::Document
# mount_uploader :file, PictureUploader
# end
#
# This will NOT work with reprocessing through Rake because the mounted_uploader uses the "file" attribute.
namespace :carrierwave do
##
# Only tested with Amazon S3 Storage
# Needs some minor modifications if you want to use this for File System Store, Cloud Files and GridFS probably.
# This should work without Ruby on Rails as well, just set a different TMP_PATH.
desc "Reprocesses Carrier Wave file versions of a given model."
task :reprocess => :environment do
##
# Load in the OPEN URI library to be able
# to pull down and store the original file in a temp directory
require 'open-uri'
##
# Default constants
TMP_PATH = "#{Rails.root}/tmp/carrierwave"
##
# Set environment constants
CLASS = ENV['class'].capitalize
ASSOCIATION = ENV['association'] || nil
MOUNTED_UPLOADER = ENV['mounted_uploader'].to_sym
VERSIONS = ENV['versions'].nil? ? Array.new : ENV['versions'].split(',').map {|version| version.strip.to_sym}
##
# Find the Model
MODEL = Kernel.const_get(CLASS)
##
# Create the temp directory
%x(mkdir -p "#{TMP_PATH}")
##
# Find all records for the provided Model
records = MODEL.all
##
# Output to console
puts "\nCarrier Wave Version Reprocessing!"
puts "======================================="
puts "Model: #{CLASS}"
puts "Mounted Uploader: #{MOUNTED_UPLOADER}"
puts "Association: #{ASSOCIATION}" if ASSOCIATION
puts "Versions: #{VERSIONS.empty? ? "all" : VERSIONS.join(', ')}\n\n"
##
# Run through all records
records.each do |record|
##
# Set the mounted uploader object
# If it has a one-to-one association (singular) then that object
# will be returned and wrapped in an array so we can "iterate" through it below.
#
# If it has a one-to-many association then it will return the array of associated objects
#
# If no association is specified, it assumes the amounted uploader is attached to the specified CLASS
if ASSOCIATION
if ASSOCIATION.singular?
objects = [record.send(ASSOCIATION)]
else
objects = record.send(ASSOCIATION)
end
else
objects = [record]
end
##
# Iterates through the objects
objects.each do |object|
##
# Returns the mounted uploader object
mounted_object = object.send(MOUNTED_UPLOADER)
##
# Retrieve Filename
filename = mounted_object.path.split('/').last
##
# Output to console
puts "Reprocessing: #{filename}"
##
# Read out the original file from the remote location
# and write it out to the temp directory (TMP_PATH)
# This file will be used as the base file to reprocess
# the versions. Once all versions have been processed,
# this temp file will be directly removed.
open(mounted_object.url) do |original_object|
File.open(File.join(TMP_PATH, filename), 'w') do |temp_file|
temp_file.write(original_object.read)
end
end
##
# By default it will add all available versions to the versions variable
# which means that all available versions will be reprocessed.
# If the "versions" argument has been provided, then only the specified
# version(s) will be set to the versions variable, and thus, only these
# will be reprocessed.
versions = mounted_object.versions.map {|version| version[0]}
versions = VERSIONS unless VERSIONS.empty?
##
# Reprocesses the versions
versions.each do |version|
mounted_object.send(version).cache!(File.open(File.join(TMP_PATH, filename)))
mounted_object.send(version).store!
end
##
# Removes the temp file
%x(rm "#{TMP_PATH}/#{filename}")
end
end
end
end
The problem is that while it creates the new images, the files are saved under a new file name rather than following the naming laid out in the image uploader, so the website cannot find them. The following is an example of how the images are stored.
How it should be:
Original file:
fdk392ks93_39ei.png
thumbnail version:
thumb_fdk392ks93_39ei.png
How it is:
Original file:
fdk392ks93_39ei.png
thumbnail version:
thumb_fajeilkadifej_jakdjfi.png
Any help would be very appreciated.
Other info:
Model: User
Uploader: user_image (this is also the column name which stores the folder/file name)
After calling recreate_versions! you have to call save! on the model. You can check out this question where someone asked basically the same thing.
The README clearly states how to recreate Carrierwave versions:
https://github.com/jnicklas/carrierwave/blob/master/README.md
"You might come to a situation where you want to retroactively change a version or add a new one. You can use the recreate_versions! method to recreate the versions from the base file. This uses a naive approach which will re-upload and process the specified version or all versions, if none is passed as an argument.
instance = MyUploader.new
instance.recreate_versions!(:thumb, :large)
Or on a mounted uploader:
User.all.each do |user|
user.avatar.recreate_versions!
end
I have a Rails 3.1 app, which utilizes the Shopify API gem to fetch some external data via ActiveResource. We store these ActiveRecord model objects in Memcached via Dalli, and then read in again when needed.
We can successfully read in this data when running the Thin webserver, and everything works fine. However, once I setup Unicorn as the webserver then I continue to get the following error when reading the model object from Memcached:
Cache read: shopcache_987102
DalliError: Unable to unmarshal value: undefined class/module ShopifyAPI::Order::ClientDetails
Completed 500 Internal Server Error in 395ms
This does not happen on every read, but regularly enough to be a big problem. It only happens when we spawn more than 1 Unicorn worker process.
Below is my unicorn.rb file:
worker_processes 3
timeout 30
preload_app true
after_fork do |server, worker|
#Re-connect to ActiveRecord
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
Rails.logger.info('Connected to ActiveRecord')
end
end
We also have the following activated:
config.cache_classes = true
If I only spawn up a single Unicorn worker_process (worker_processes 1) then all works fine. I have tried setting config.threadsafe! in application.rb and this does not help with multiple workers.
It seems that the needed class/module is not being required, and I cannot work out why.
EDIT:
I've also added the following to my applicaton.rb file to try and add the gem to the autoload path of rails, without success:
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
I've also added to the application_controller.rb require_dependency 'shopify_api' like so:
require 'current_shop_detail'
class ApplicationController < ActionController::Base
protect_from_forgery
include CurrentShopDetail
require_dependency 'shopify_api'
end
but I'm unsure if this is the correct way to do a require_dependency, seeing as the missing class is: ShopifyAPI::Order::ClientDetails
Any ideas? Thanks :)
I have the following file uploader
class ItemImageUploader < CarrierWave::Uploader::Base
include ::CarrierWave::Backgrounder::Delay
include CarrierWave::MiniMagick
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
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
asset_path("fallback/" + [version_name, "image.png"].compact.join('_'))
end
def cache_dir
"uploads/tmp"
end
# Create different versions of your uploaded files:
version :thumb do
process :resize_to_fill => [80,80]
end
def extension_white_list
%w(jpg jpeg gif png)
end
Picture class
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
mount_uploader :image, ItemImageUploader
process_in_background :image
validates_presence_of :image
def copy
Picture.new(:image => self.image)
end
And the following config in carrier_wave.rb initialization file:
CarrierWave.configure do |config|
config.enable_processing = true
#config.permissions = 0666
#config.directory_permissions = 0777
config.storage = :file
end
Images uploaded properly, but no thumbnails created, no errors occurred. Please advise.
Just hit my head against this one myself. As the comments suggest, using carrierwave_backgrounder causes this problem. You can see it in their documentation:
process_in_background - This stores the original file with no processing/versioning.
Doesn't help with a solution, but I thought I'd verify the problem.
I struggled with this for a couple of hours today, because I had the same issue. Uploading of the original version would work, but it was not resized. It was working locally, but not on my production machine. Hope someone with the same issues stumbles on this answer and saves some time.
Turned out that my version of ImageMagick was not build with the correct delegates, this was the output of $ convert -version:
Version: ImageMagick 6.9.1-10 Q16 x86_64 2015-08-01 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC OpenMP
Delegates (built-in): zlib
I used this answer to install the delegates and build a fresh version of ImageMagick: ImageMagick missing decode delegates
After that, pulled up the ImageMagick info with $ convert -version:
Version: ImageMagick 6.9.1-10 Q16 x86_64 2015-08-01 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC OpenMP
Delegates (built-in): bzlib djvu fontconfig freetype gvc jbig jng jpeg lcms lqr lzma openexr png tiff wmf x xml zlib
And now I'm rollin'!