Datamapper + Carrierwave store method not being called, only cache - ruby

I have a really simple sinatra app which uses datamapper and carrierwave.
I've reduced the uploader to its minimum:
class PhotoUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
end
And have one simple model that uses it:
class Photo
include DataMapper::Resource
property :id, Serial
property :caption, String
property :position, Integer
property :created_at, DateTime
property :updated_at, DateTime
mount_uploader :source, PhotoUploader
belongs_to :album
end
It happens that when I use it:
post '/admin/album/:id/photo/create' do
album = Album.get(params[:id])
photo = Photo.create(params[:photo])
album.photos << photo
album.save!
redirect '/admin/album'
end
photo is being created normally on the database and the file is being uploaded normally to the cache directory but not being moved to the final storage destination.
I've got into the carrierwave code and could verify that the cache! method is being called but not the store! method.
I've tried to use the uploader without any association to the object:
get '/lorem' do
f = File.open('test.png')
u = PhotoUploader.new
u.store!(f)
"ok"
end
Everything works as expected in this case.
==================== UPDATE ====================
I belive I've found the source of the problem. While running debugger I got to this:
gems/dm-core-1.2.0/lib/dm-core/query.rb:1014
conditions.each do |condition|
(rdb:1)
gems/carrierwave-0.6.2/lib/carrierwave/sanitized_file.rb:290
def sanitize(name)
(rdb:4)
gems/carrierwave-0.6.2/lib/carrierwave/sanitized_file.rb:299
def split_extension(filename)
(rdb:4)
gems/carrierwave-0.6.2/lib/carrierwave/sanitized_file.rb:29
self.file = file
(rdb:4)
gems/carrierwave-0.6.2/lib/carrierwave/sanitized_file.rb:269
if file.is_a?(Hash)
(rdb:4)
gems/carrierwave-0.6.2/lib/carrierwave/sanitized_file.rb:274
#file = file
(rdb:4) pp file
"/Users/jvalente/Projects/dummy/public/uploads/{:filename=>\"Screen Shot 2013-01-24 at 4.57.15 PM.png\", :type=>\"image/png\", :name=>\"photo[source]\", :tempfile=>#<File:/var/folders/jp/wm1gxk8558d36rh9vzkmx4jw0000gn/T/RackMultipart20130128-27245-105ybbf>, :head=>\"Content-Disposition: form-data; name=\\\"photo[source]\\\"; filename=\\\"Screen Shot 2013-01-24 at 4.57.15 PM.png\\\"\\r\\nContent-Type: image/png\\r\\n\"}"
This clearly is wrong since it will fail the file.is_a?(Hash) condition and get into:
#file = file
#original_filename = nil
#content_type = nil
Still, I can't understand why this happens.

Related

How to fix a "value too long for type character varying(255)" error

I'm trying to save a file so that I can upload it to stripe using CarrierWave, but I'm getting the error:
ERROR: value too long for type character varying(255)
and don't understand why as I followed the CarrierWave usage guide on GitHub.
This is my application:
class SplitterStripeServer < Sinatra::Base
CarrierWave.configure do |config|
config.root = File.dirname(__FILE__) + "/public"
end
post "/" do
img = Image.new
img.file = params[:file] #carrierwave will upload the file automatically
img.save!
redirect to("/")
end
get "/upload" do
erb :upload
end
get "/" do
#image = Image.find(1)
erb :index
end
end
This is the uploader:
class ImagesUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
end
This is the model:
class Image
include DataMapper::Resource
property :id, Serial
mount_uploader :file, ImagesUploader
end
I feel like I'm missing something simple.
You need to decrease a length of a file name. Override filename method and cut a file's basename e.g. to 250 characters.
class ImagesUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def filename
"#{file.basename[0..250]}.#{file.extension}" if original_filename.present?
end
end
check if you have additional installed gems
I had was installed gem validates_lengths_from_database and this gem doesn't understand how to work with carrierwave. I am just turn off it in model validates_lengths_from_database except: %i[file]

Saving a csv file with sinatra and datamapper

Trying to do as the title says using carrierwave but not having much luck as i get the following error:
TypeError - no implicit conversion of CsvFile into String:
here is my post method where it fails:
post '/file' do
file_data = params[:csv_file][:tempfile]
file_name = params[:csv_file][:filename]
file_path = "app/public/csv_files/#{file_name}"
date = Time.now.strftime("%d/%m/%Y %H:%M")
csv_file = CsvFile.new(name: file_name,
path: file_path,
date: date,
file: file_data
)
file = CSV_File_Reader.new(file_path)
erb(:finished)
end
and here is my CsvFile class:
class CsvFile
include DataMapper::Resource
property :id, Serial
property :name, String
property :path, String
property :date, String
mount_uploader :file, File
has n, :images
end
All the params come through as they should but as I'm fairly new to this I'm clearly missing something and googling hasn't worked for me. Any help would be great. Thanks

Where does CarrierWave stores uploads

Please help me understand how does CarrierWave works.
I'm using minimal Sinatra/DataMapper app with following contents:
class VideoUploader < CarrierWave::Uploader::Base
storage :file
end
class Video
include DataMapper::Resource
property :id, Serial
property :name, String
property :desc, Text
mount_uploader :file, VideoUploader
end
get '/' do
slim :form
end
post '/' do
video = Video.new
video.name = params[:name]
video.desc = params[:desc]
video.file = params[:file]
video.save
redirect '/'
end
As I understood mount_uploader :file, VideoUploader string in Video definition adds .video method to Video instance, and I can store uploads assigning params[:file] to it. When I'm trying to send form from browser, the request successfully creates record in DB table, but I can't find any signs of file existence either in DB and public_directory. What I'm doing wrong?
You probably should define the store_dir method inside the VideoUploader class:
class VideoUploader < CarrierWave::Uploader::Base
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
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
....
end

Who can explain how this code block works: Carrierwave MD5 as filename

I am using the Carrierwave gem with a Sinatra app to upload and store images.
I am following How to: Use file's MD5 as filename and everything works as expected. However I do not understand how the following piece of code provided on the how-to page works:
class ImageUploader < CarrierWave::Uploader::Base
storage :file
def md5
chunk = model.send(mounted_as)
#md5 ||= Digest::MD5.hexdigest(chunk.read)
end
def filename
#name ||= "#{md5}#{File.extname(super)}" if super
end
end
I in particular do not understand what model.send(mounted_as)does, what the ||= operator means, and why the if super conditional is used (and what it does).
Could somebody please explain this to me?
Say, for example the model is Person and the ImageUploader is mounted as avatar.
class Person < ActiveRecord::Base
mount_uploader :avatar, ImageUploader
end
Then, the md5 method would be calling something to the affect of chunk = person.avatar and using this to calculate the hash of the file contents, which you want for the name.
The filename method checking to see if there is a #filename instance variable, as defined in the CarrierWave::Uploader::Store class.
class CarrierWave::Uploader::Store
def filename
#filename
end
end
Then calling this again to get the filename extension to use in the constructed filename. The #name variable is then just a temporary cache of the name, so that future calls to the method do not require the whole thing to be calculated again.
Edit:
The carrierwave uploader has methods/instance variables for the model (eg Person instance) and declared mount point in the model (eg avatar). These are from the mount_uploader declaration in your active record model.
module CarrierWave::Uploader::Mountable
attr_reader :model, :mounted_as
def initialize(model=nil, mounted_as=nil)
#model = model
#mounted_as = mounted_as
end
end
These are used for various things, as well as being made available for us to do things just such as you are trying. It is just an abstract way to call person.avatar, which returns the file (File instance not string path). This is then read into the MD5 lib, which gives the hexdigest.
Rewriting this in more plain terms
class ImageUploader < CarrierWave::Uploader::Base
def md5
uploaded_file = model.send(mounted_as) # person.avatar (File instance)
#md5 ||= Digest::MD5.hexdigest(uploaded_file.read) # hexdigest of file content
end
end

Image upload in ruby with sinatra and datamapper and Carrierwave?

I want to upload a single image with Carrierwave, the thing is, it is uploading the file and saving it into the directory uploads, in this folder it creates another folder called tmp, and in the tmp folder it creates another folder which includes the image.
The thing is it doesn't seem to stop it is uploading and uploading and uploading all the time even if the image is fully uploaded into that folder and I can open this image already with feh(or anyother image viewer).
This is what my controller looks like.
get "/new" do
protect!
erb :new
end
post "/new" do
protect!
#user = User.get(session[:user_id])
image = #user.image.new(
:description => params[:description],
:image => params[:image]
)
# image.save
"NEVER REACHED!"
end
(The text "NEVER REACHED!" won't be displayed at all and I don't know why...)
This is my model:
class ImageUploader < CarrierWave::Uploader::Base
def extensions_white_list
%w(jpg jpeg gif png)
end
storage :file
end
class Image
include DataMapper::Resource
property :id, Serial
property :description, Text
property :image, String, :auto_validation => false
mount_uploader :image, ImageUploader
end
class User
include DataMapper::Resource
property :id, Serial
has n, :post
end
So as already mentioned the Text "NEVER REACHED" is never reached. Any Ideas why?
Besides I always get the warning:
Defining property for an uploader is deprecated at /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
And I do not know why...
UPDATE: It is somehow working now as long as I do not uncomment image.save in the main controller, but I actually need to uncomment this, any Ideas how to fix this?
Remove property :image line in your Image model as:
class Image
include DataMapper::Resource
property :id, Serial
property :description, Text
mount_uploader :image, ImageUploader
end
mount_uploader by itself defines the :image as String type.
Try to run your application after this and let me know if the condition remains the same. :)

Resources