Heroku, CarrierWave, MiniMagick: random tmp file missing - ruby-on-rails

in my RoR project I am using CarrierWave + MiniMagick and deployed to Heroku for production.
I have this problem in production that sometimes the tmp file is missing for image processing. I get this error:
Errno::ENOENT: No such file or directory - /tmp/mini_magick20130319-2-3wq6l6.jpg
I have other XUploader classes that works but this particular one have two image processes. Initially I had two separate process for this:
process :resizer
def resizer
resize_to_fit(model.jrac_image_width, model.jrac_image_height)
end
process :cropper
def cropper
manipulate! do |img|
img.crop("442x190+#{model.jrac_crop_x}+#{model.jrac_crop_y}")
img
end
end
but it said I was having error on :cropper saying the tmp file doesn't exist. I tried to change the code to this, hopefully it will only work on it once:
process :resize_and_crop
def resize_and_crop
manipulate! do |img|
img.resize("#{model.jrac_image_width}x#{model.jrac_image_height}") # resize_to_fit
img.crop("442x190+#{model.jrac_crop_x}+#{model.jrac_crop_y}") # cropper
img
end
end
but unfortunately, still experiencing the same errors.
Does anyone have any idea where the problem is? I don't know if it's with Heroku or CarrierWave or ImageMagick?
Edit
I also have this code on my Uploader class
def cache_dir
"#{Rails.root}/tmp/uploads"
end
as for this document.

heroku will empty the tmp from time to time, usually, we use s3 or other cloud storage to store the processed version. You may refer to https://github.com/jnicklas/carrierwave and
https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Make-Carrierwave-work-on-Heroku
They have detailed walkthrough on using carrierwave in heroku
I have tried that before and it works

Related

Saving image created with RMagick using Rails and CarrierWave

In my Rails app I have a module that takes several images, and using RMagick "stitches" them together into a new single image. I'm able to successfully create the final image, but I'm having trouble saving this new image as an attachment to a model (using CarrierWave). The method that does the stitching looks like this:
def generate_collage(params)
final_image = ImageList.new
# ... code that puts together the composite image ...
return final_image.append(true).to_blob { |attrs| attrs.format = 'JPEG' }
end
I've got my User model with an uploader mounted:
class User < ActiveRecord::Base
mount_uploader :image, UserImageUploader
end
In the CarrierWave documentation under the ActiveRecord section, they show how to assign a new image, but they assume the file already exists somewhere. In my case it doesn't yet exist on the filesystem, and I'm outputting a blob... is there any way to go from that blob to generating an image upload for CarrierWave?
I suppose I'm trying to avoid saving this image temporarily into "#{Rails.root}/tmp/" and then reading it from there... it seems like I could cut out this step and send directly to CarrierWave somehow, but I don't know how! Is it possible?
I'm working on something similar right now. This should be possible, but an easy workaround is to save it to a temp file:
temp_file = Tempfile.new([ 'temp', '.png' ])
image.write(temp_file.path)
user = User.new
user.avatar = temp_file
user.save
temp_file.close
temp_file.unlink
I'm hoping to try to improve it to remove the file system dependency completely, by following the advice in one of these answers: How to handle a file_as_string (generated by Prawn) so that it is accepted by Carrierwave?

Rails convert Paperclip directory structure to Carrierwave

I was using the Paperclip gem: https://github.com/thoughtbot/paperclip
I'm now using Carrierwave: https://github.com/carrierwaveuploader/carrierwave
My production website is currently using Paperclip. I'm going to be updating the production website to use Carrierwave.
The folder structure for uploads in Paperclip differs from Carrierwave.
I'm also using Amazon S3 to store uploads.
I'm wondering if there's a way to convert my production files uploaded with Paperclip to Carrierwave.
For example, with Paperclip in production I currently have something like the following for resumes:
bucket_name/model_name/resume/000/000/model_id/original/test.pdf
With Carrierwave it should be:
bucket_name/uploads/model_name/resume/model_id/original/test.pdf
Right now it seems I have to make this conversion manually. I was wondering if there's a better approach.
Please advise.
The CarrierWave::Compatibility::Paperclip module already provides this functionality. Just do the following in your uploader:
class MyUploader < CarrierWave::Uploader::Base
include CarrierWave::Compatibility::Paperclip
# The :id_partition symbol will trigger a proc in the Paperclip compatibility module that will build out the properly partition directory structure
def store_dir
"#{model.class.to_s.underscore}/#{mounted_as.to_s}/:id_partition"
end
end
Have you tried changing the store_dir options define in carrierwave uploader to look exactly like that of paperclip
def store_dir
"#{model.class.to_s.underscore}/resume/#{id_partitioning}/original/"
end
def id_partitioning
("%09d" % model.id).scan(/.{3}/).join("/")
end
Note : I just done remember how the paperclip does the id_partitioning (how much '0' it pad to the left based on object id )
but based upon your format 000/000/model_id look to me like 9 character Please confirm
Hope this help

Make CarrierWave to not copy original file for versions

As I understand it for each version defined in an uploader CarrierWave will copy original file from cache to tmp path and hand over this tmp file to whatever processing is defined for this version. Then it can store all files. Sometimes (e.g. when generating thumbnail for videofile) this copying can be prohibitively expensive. Can I make CarrierWave to not copy and to let me generate versions from the original file while it's in cache?
Edit I have move_to_cache and move_to_store to return false true (oops I forget my own head soon). And I wrote a test processing module on the lines of CarrierWave::RMagick:
module CarrierWave
module Thumbnailer
def generate_thumbnails
debugger
x = 1
end
end
end
and I have the following lines inside the uploader
version :thumb do
process :generate_thumbnails
end
But when execution is stopped on the debugger (that's where I can start processing) CarrierWave has already copied and renamed the uploaded file. I can see both of them inside the cache directory.
Check out the readme under Large Files ... from the README:
class MyUploader < CarrierWave::Uploader::Base
def move_to_cache
true
end
def move_to_store
true
end
end
When the move_to_cache and/or move_to_store methods return true, files
will be moved (instead of copied) to the cache and store respectively.

How to stub carrierwave in Rspec?

I want to stub carrierwave to prevent it from fetch images on the web during my tests. How would I stub things to achieve this?
My crawler parses a remote web page, and saves one image url into the model. Carrierwave will fetch that image automatically during the save operation. It works well.
However I have a test about the parsing of pages, and every-time it will download the file, which slows down the testing.
UPDATE:
I mount the uploader as the following (in the pre-existing paperclip column)
mount_uploader :image, TopicImageUploader, :mount_on => :image_file_name
I tried to stub the following, but neither worked:
Topic.any_instance.stub(:store_image!)
Topic.any_instance.stub(:store_image_file_name!)
Topic.any_instance.stub(:store_image_remote_url!)
TopicImageUploader.any_instance.stub(:download!)
This is what I'm using in my spec_helper:
class CarrierWave::Mount::Mounter
def store!
end
end
This completely blocks all real file uploads (note that I'm using this with carrier wave 0.5.8, which is newest version at the time of writing, if you're using much older version, it might differ). If you want to control tests which stub uploads, you could use:
CarrierWave::Mount::Mounter.any_instance.stub(:store!)
I reduced my test-suite time from 25 seconds to just 2 seconds with a simple config in the CarrierWave initializer:
# config/initializers/carrier_wave.rb
CarrierWave.configure do |config|
config.enable_processing = false if Rails.env.test?
end
This config skips the image manipulation (resizing, cropping, ...) of ImageMagick, MiniMagick ect.
allow_any_instance_of(CarrierWave::Uploader::Base).to receive(:store!).and_return nil

carrierwave uploader uploads file, but still serves up default_url

I'm using carrierwave in a rails 3 application to upload and store a file from a remote source in my server's file system. I've got a setup that's totally standard, with an uploader mounted on the model that the image is associated with.
It works perfectly 99.9% of the time, but every 600th graph or so I run into an issue where the app persistently fails to serve the stored image. If I check on the filesystem, the graph image has been uploaded and stored in the correct location, with the correct file permissions and everything, but rails is totally unaware of it and continues to serve the default graph image for that instance.
In other words a graph with id 123 has it's image stored at /uploads/graphs/123/graph.png ... the correct image is there but as far as rails is concerned it has no image stored. All the other graph images still work fine, but I can't get rails aware of the image stored for 123. Removing and re-storing the image doesn't work. Manually removing the image and re-uploading doesn't work. I'm totally lost. The graph instance is valid, no errors in the logs when I save.
for example, in the console:
g = Goal.find_by_id("123")
g.remote_graph_url = "http://image.source/url.png"
> "http://image.source/url.png"
g.save
> true
g.graph?
> false
g.graph_url >> /default/image.png
here's the relevant code:
class GraphUploader < CarrierWave::Uploader::Base
def store_dir
"../uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def default_url
"/images/" + [version_name, "default_large_graph.png"].compact.join('_')
end
def extension_white_list
%w(jpg jpeg gif png)
end
def filename
"graph.png" if original_filename
end
end
class Graph
mount_uploader :graph, GraphUploader
end
Wish I could just reply...
So you are saving uploads outside of the public directory? Try removing the "../" before images, if that wasn't your intention.

Resources