Cannot upload image by carrierwave - ruby-on-rails

I am using carrierwave to upload my image but failed. Please help me.
Versions used:
rails (4.0.1)
carrierwave (0.10.0)
carrierwave-mongoid (0.7.1)
carrierwave_backgrounder (0.4.1)
My uploader:
#<EventImageUploader:0x007fc6a948ede8
#model=#<Event::EventImage
_id: 5876f63b6c616cea34630000,
c_at(created_at): 2017-01-12 03:21:31 UTC,
image: nil,
image_tmp: "1484191291-59956-9524/2016-12-10_23-45.jpg">,
#mounted_as=:image>
My image is nil, but the image under image_tmp exists. My sidekiq is running fine too.
Here is my worker:
class ImageWorker < ::CarrierWave::Workers::StoreAsset
def perform(*args)
super(*args)
record = ::CarrierWave::Workers::Base.perform(*args)
if record
p "success"
else
raise "record #{args} not found, failed"
end
end
end
How to make the upload works? Thank you.

After viewing the source of CarrierWave::Workers::StoreAsset#perform,
the reason why the image cannot be uploaded is because of embedded documents.
The line from source record = resource.find id will return nil because resource is an embedded class and you cannot find id by an embedded class.
To solve the problem, see here. My code should work if I add the following:
class Event
include Mongoid::Document
embeds_many :images
end
class EventImage
include Mongoid::Document
embedded_in :Event
mount_uploader :image, ImageUploader
process_in_background :image
def self.find(id)
bson_id = Moped::BSON::ObjectId.from_string(id) # needed for Mongoid 3
root = Event.where('images._id' => bson_id).first
root.images.find(id)
end
end
If you get the error uninitialized constant Moped::BSON, make sure to require it in the first place.

Related

Rails paperclip default image only under certain conditions

I've got a Lead model which is splited by lead_status param on products and offers. Only leads with product status should contain images and offers should not. I've migrated attached product_image table to schema and tried to set a default image only for products. Like this:
class Lead < ApplicationRecord
has_attached_file :product_image, styles: { small: "150x150>", default: "350x350"}
validates_attachment_content_type :product_image, content_type: /\Aimage\/.*\z/
before_save :product_image_default_url
def product_image_default_url
if self.lead_status == "product" && self.product_image.url.nil?
self.product_image.url = "/images/:style/default_user_avatar.png"
end
end
Every time when I save a new lead without uploaded image I get "/product_images/original/missing.png" as a default url. No matter which status it has.
Model doesn't recognize new leads by it's status
How can I change that? Force my Lead model to save a default image url according to a "product" status and ignore all those with "offer" status?
My rails version is 5.2.1 and paperclip 6.0.0
Try with following,
has_attached_file
:product_image,
styles: { small: "150x150>", default: "350x350"},
default_url: ":style/default_user_avatar.png"
# app/assets/images/medium/default_user_avatar.png
# app/assets/images/thumbs/default_user_avatar.png
Existing method is,
def default_url
if #attachment_options[:default_url].respond_to?(:call)
#attachment_options[:default_url].call(#attachment)
elsif #attachment_options[:default_url].is_a?(Symbol)
#attachment.instance.send(#attachment_options[:default_url])
else
#attachment_options[:default_url]
end
end
In initializer, Provide monkey patch for following,
require 'uri'
require 'active_support/core_ext/module/delegation'
module Paperclip
class UrlGenerator
def default_url
if #attachment.instance.lead_status == 'product'
default_url = attachment_options[:default_url]
else
default_url = # provide another missing default_url
end
if default_url.respond_to?(:call)
default_url.call(#attachment)
elsif default_url.is_a?(Symbol)
#attachment.instance.send(default_url)
else
default_url
end
end
end
end
Update as per cases

Additional fields in CarrierWave Uploader

I am trying to add additional fields to the CarrierWave Uploader so that they are stored as part of the Uploader itself and together with the CarrierWave fields, such as #file, #model, #storage etc.
The fields are also version-specific, which is why I'd prefer to be able to access them via <my_model>.<my_uploader>.attribute and<my_model>.<my_uploader>.versions[:<the_version>] instead of additional columns in the model.
I did try the carrierwave-meta gem, but ran into an error with it ( NoMethodError: undefined method \'original_filename' for #<CarrierWave::Storage::Fog::File:0xab4134c> )
that seems to not have been fixed yet.
Any ideas or suggestions on how to best accomplish this?
I'm not 100% clear what you are trying to do.
when I use carrierwave gem, I do create a path that holds some of that information. In my applaications I normally have a file app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
def store_dir
# "uploads/image/file/187/"
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
...
end
from this I always know the model, what type of file, and the id.
All other info about this model I normally save in the database.
I hope this helps and sets you in the right direction
your error is connected with fog
In my Picture Uploader I can set an attribute reader and writer
class PictureUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def field
#field
end
def field=(field)
#field = field
end
# attr_accessor :field # for an even shorter way
end
The I open the rails console to test the model:
picture = PictureUploader.new
=> #<PictureUploader:0x0055804db336e8 #model=nil, #mounted_as=nil>
picture.field=('your text')
=> "your text"
picture.field
"your text"
About the versioning and error you are having 'NoMethodError: undefined method \'original_filename' for #<CarrierWave::Storage::Fog::File:0xab4134c>' I agree with MZaragoza
CarrierWave::Storage::Fog::File.new takes three parameters
def store!(file)
f = CarrierWave::Storage::Fog::File.new(uploader, self, uploader.store_path)
f.store(file)
f
end
uploader, self and uploader.store_path so to help us solve this problem you should include your CarrierwaveUploader model code and the output of uploader.store_path
Thanks a lot

Getting error using CarrierWave with RMagick processing

I am using Rails 4, and trying to upload an image and then store it after processing it.
I am using just one view, where I want the user to upload the image, I process the image, store it in db, and then reload the page with the new processed image.
My model (user.rb)
class User < ActiveRecord::Base
mount_uploader :image, ImageUploader
end
Uploader (image_uploader.rb)
# encoding: utf-8
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
process :changeImage
def changeImage
manipulate! do |source|
source = source.sepiatone
end
end
Controller (app_main_controller.rb)
require 'Rmagick'
class AppMainController < ApplicationController
def index
# page reload handling when the file uploads
if(params.has_key?("file-input"))
#u= User.new
#u.image = params["file-input"]
if(#u.save)
render js: "alert('SAVED')"
else
render js: "alert('Error while saving image! Try Again!')"
end
# initial page load
else
end
end
end
I access the image-uploader in my view (i.e. index) with image_tag #u.image_url
I keep on getting "stack level too deep" everytime I add any kind of processing in image_uploader.rb. If no processing is added, the image gets uploaded fine.
Any ideas, anyone?
I am experiencing the same problem. It looks like an issue with the rmagick gem.
EDIT:
The problem is with case. Try this instead:
gem 'rmagick', :require => 'RMagick'
See also this stackoverflow answer and this issue or this issue on github.
I switched to mini_magick to fix it. (Not ideal, but it's working for me now.)
Uploader class (comment out RMagick):
include CarrierWave::MiniMagick
Gemfile:
gem 'mini_magick'

Sidekiq repeating the same job over and over

I am essentially writing the project in Railscast 383 - the second part, when the photo is uploaded directly to AWS S3, and the photo is then processed in the background by Sidekiq to create a thumbnail version of the photo. I'm on Rails 4.
My issue is that the Sidekiq job, after completing successfully, keeps repeating over and over, instead of just stopping.
Where am I going wrong? I can't see any difference between my code and that of the Railscast, other than I'm on Rails 4 (so strong parameters instead of attr_accessible)
Photo class:
class Photo < ActiveRecord::Base
mount_uploader :image, ImageUploader
default_scope order('updated_at DESC')
after_save :enqueue_image
def image_name
File.basename(image.path || image.filename) if image
end
def enqueue_image
ImageWorker.perform_async(id, key) if key.present?
end
end
ImageWorker:
class ImageWorker
include Sidekiq::Worker
sidekiq_options retry: false
# sidekiq_options retry: 3
def perform(id, key)
photo = Photo.find(id)
photo.key = key
photo.remote_image_url = photo.image.direct_fog_url(with_path: true)
photo.save!
photo.update_column(:image_processed, true)
end
end
Uploader:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWaveDirect::Uploader
include CarrierWave::RMagick
# storage :fog
#### storage defaults to fog when CarrierWaveDirect::Uploader is included ####
include CarrierWave::MimeTypes
process :set_content_type
version :thumb do
process :resize_to_limit => [200, 200]
end
version :medium do
process :resize_to_limit => [400, 400]
end
end
One reason for the sidekiq worker to be called again and again is because the perform_async is called every time you save your photo object, which occurs within the sidekiq worker itself.
So every time the ImageWorker is called, it saves the photo, calling the ImageWorker again, creating the loop you are experiencing.
Are you sure you aren't missing a check for the :image_processed tag to be true before calling the ImageWorker again.
Try this:
def enqueue_image
ImageWorker.perform_async(id, key) if key.present? && !image_processed
end
This will check if the image was processed once before. I think this was probably meant to be set in the rails cast but the author forgot about it, otherwise the image_processed flag is obsolete.

Carrierwave Mongoid validation of file

I cant figure out how to validate that carrierwave has uploaded a document to my mongoid object.
i have a Document Class
class Content::Document < Content
mount_uploader :attachment, DocumentUploader
field :attachable_id
field :attachable_type
end
and an uploader:
require 'carrierwave/orm/mongoid'
class DocumentUploader < CarrierWave::Uploader::Base
storage = :filesystem
include CarrierWave::RMagick
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_white_list
%w(doc docx xls xlsx ppt pptx pdf )
end
i would like to validate that the upload exists and that it matches the white list else through a standard validation error
this is on Rails 2.3.8
While it's true that Carrierwave does have extensive tests, you could test for validity with something like this:
it "is valid with valid attributes" do
file_bytes = File.open("spec/binary/avatar.png")
valid_attrs = {:name => "foo", :description => "bar", :avatar => file_bytes}
user = User.new(valid_attrs)
user.should be_valid
end
Hope that helps!
In general you don't need to do that since this behaviour is already tested in carrierwave specs itself.
You can test your uploaders in isolation, using Carrierwave test helpers. E.g. I would just write a spec like
attachment_uploader.extension_white_list.should =~ %w(doc docx xls xlsx ppt pptx pdf)
But if you insist on testing that I would suggest using FakeFS to stub filesystem and then check with
File.exists? document.attachment.current_path
whether attachment has been created.

Resources