My model
class Article < ActiveRecord::Base
LOGO_TYPES = ['image/jpeg', 'image/png', 'image/gif']
VALID_LOGO_MESSAGE = 'Please attach a valid picture file containing your organization logo. Valid formats are JPG, PNG, and GIF'
has_attached_file :logo, :content_type => LOGO_TYPES,
:path => ":rails_root/app/assets/images/uploads/articlelogos/:id/:style/:basename.:extension",
:url => "/assets/uploads/articlelogos/:id/:style/:basename.:extension"
validates_attachment_content_type :logo, :content_type => LOGO_TYPES, :message => VALID_LOGO_MESSAGE
validates_attachment_size :logo, :less_than => 1.megabytes
end
When I try to upload a valid, 6k .gif logo using Paperclip, I get:
Logo_file_size file size must be between 0 and 1024 bytes
Logs as request hits :
Started PUT "/articles/74" for x.x.x.x at 2012-01-15 17:44:20 -0600
Processing by ArticlesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"uI+OXmV3B/crOrUopbBxpRs242PzMVJY1uM/QBnHdlE=", "article"=>{"logo"=>#<ActionDispatch::Http::UploadedFile:0x000000081d70b0 #original_filename="test_logo.gif", #content_type="image/gif",
#headers="Content-Disposition: form-data; name=\"article[logo]\"; filename=\"test_logo.gif\"\r\nContent-Type: image/gif\r\n",
#tempfile=#<File:/tmp/RackMultipart20120115-30606-1wwkr21>>}, "commit"=>"Upload Now", "id"=>"74"}
And I added some debugging to show the tempfile
params[:article][:logo].inspect: #<File:/tmp/RackMultipart20120115-30606-1wwkr21>>
params[:article][:logo].size: 6531
So it is clearly being stored on the server, but Paperclip is failing to check the size properlly.
This works on my local Mac in development mode, but fails on production under Ubuntu.
Any ideas? Thanks!
Update - removing size validation enables the file to be uploaded and stored as usual
Related
I'm trying to upload an image using Paperclip; I followed the paperclip quick start guide as closely as possible, but I'm doing something wrong and can't find out what. I'm new to Ruby and Rails; the whole project is set up with the AngularJS framework.
What I'm doing is sending a POST request that contains a base64 encoded image:
DataService.add("uploads", {image: file}) [...]
The service looks like this:
add: function(type, object) {
return $http.post(API_URL + "/" + type, object) [...]
"file" is the base64 encoded image; I hope it is somewhat clear how the POST works. Now the backend:
Controller:
module Api
class UploadsController < ApplicationController
# POST api/uploads
def create
p params
#upload = Upload.create(upload_params)
#upload.save
end
private
def upload_params
params.require(:upload).permit(:image)
end
end
end
Model:
class Upload < ActiveRecord::Base
attr_accessor :content_type, :original_filename, :image_data
before_save :decode_base64_image
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/storage/images/:style/missing.png", :url => "/:class/:attachment/:id/:style_:basename.:extension"
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
validates :image, :attachment_presence => true
# validates_attachment :image, :size => { :in => 0..100.kilobytes }
protected
def decode_base64_image
if image_data && content_type && original_filename
decoded_data = Base64.decode64(image_data)
data = StringIO.new(decoded_data)
data.class_eval do
attr_accessor :content_type, :original_filename
end
data.content_type = content_type
data.original_filename = File.basename(original_filename)
self.image = data
end
end
end
That's basically it - I hope I included everything that's important for my problem (first question here).
When testing this with a simple image I get a 500 - Internal server error, with request payload
{"image":"data:image/png;base64,...<base64 code>...}
I understand that the mistake is most likely in the controller/model part, but I don't know how to solve this.
Thanks for your help :)
EDIT:
When testing this locally with Postman (form-data, POST, Key: upload and an image) I get this:
Started POST "/api/uploads" for 127.0.0.1 at 2015-06-13 16:34:08 +0200
Processing by Api::UploadsController#create as */*
Parameters: {"upload"=>#<ActionDispatch::Http::UploadedFile:0x00000002f0e108 #tempfile=# <Tempfile:/tmp/RackMultipart20150613-7296-8zu01e.jpeg>, #original_filename="meise.jpeg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"upload\"; filename=\"meise.jpeg\"\r\nContent-Type: image/jpeg\r\n">}
{"upload"=>#<ActionDispatch::Http::UploadedFile:0x00000002f0e108 #tempfile=#<Tempfile:/tmp/RackMultipart20150613-7296-8zu01e.jpeg>, #original_filename="meise.jpeg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"upload\"; filename=\"meise.jpeg\"\r\nContent-Type: image/jpeg\r\n">, "controller"=>"api/uploads", "action"=>"create"}
Completed 500 Internal Server Error in 0ms
NoMethodError (undefined method `permit' for # <ActionDispatch::Http::UploadedFile:0x00000002f0e108>):
app/controllers/api/uploads_controller.rb:16:in `upload_params'
app/controllers/api/uploads_controller.rb:7:in `create'
EDIT 2:
It works now, but for everyone with the same problem: if you're sending the base64 encoded image like I'm doing it in the DataService and having the same controller/module setup, it will work with Paperclip, but not with the frontend. In
has_attached_file :image, :styles => { :medium => "1000x1000>", :thumb => "150x150#" }, :default_url => "/storage/images/:style/missing.png", :url => "/:class/:attachment/:id/:style_:basename.:extension"
I had to change the last part to
"/:class/:attachment/:id/:style_image_:id.png"
Because somehow the name and extension got lost somewhere. I used the id as the file name now, and .png as an extension because the base64 is created from a png that I created in the frontend.
The problem is with this line:
params.require(:upload).permit(:image)
require ensures that a parameter is present. If it's present, returns the parameter at the given key. In your case it is returning ActionDispatch::Http::UploadedFile object which doesn't have permit method.
You can solve this by removing require and passing the file in image parameter instead of upload:
params.permit(:image)
If you want to keep the existing code, have the client pass the image in a field with name upload['image']
In Rails log, it should be like
Parameters: {"upload"=> { "image" =>#<ActionDispatch::Http::UploadedFile:0x00000002f0e108 #tempfile=# .....}}
Notice how image is inside upload.
I am new to paperclip, and I wanted to see how it would work. I generated a simple model Monkey and got the following:
rails g scaffold monkey description age:datetime
rails g paperclip monkey facepic
rake db:migrate
Model
class Monkey< ActiveRecord::Base
has_attached_file :facepic, :styles => { :medium => "300x300>", :thumb => "100x100>" }
end
View new/edit
<%= form_for #monkey, :url => monkies_path, :html => { :multipart => true } do |f| %>
...
<div class="field">
<%= f.label :facepic %><br>
<%= f.file_field :facepic %>
</div>
View show
<%= image_tag #monkey.facepic.url %>
Controller
#monkey = Monkey.new(monkey_params)
I can create new monkeys, but the show view doesn't seem to find the uploaded file. I have no error messages, except a routing error to 'missing.png'. There is no trace to the uploaded image. I am using Rails 4.1.6. What am I missing here? How do I troubleshoot this thing? The gem is installed and also imagemagick is installed.
This is what the logs say:
ActionController::RoutingError (No route matches [GET] "/facepics/original/missing.png"):
...
Started GET "/monkies/new" for 127.0.0.1 at 2014-09-19 14:40:22 +0200
Processing by MonkiesController#new as HTML
Rendered monkies/_form.html.erb (4.0ms)
Rendered monkies/new.html.erb within layouts/application (5.0ms)
Completed 500 Internal Server Error in 12ms
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"monkies"} missing required keys: [:id]):
There is no error message displayed however when I create a new monkey... :'(
EDIT:
The Monkey model is created, but the paperclip columns remain empty.
This error clearly show that your images are not getting saved because path and url not specified in your has_attached_file block. It should be like :
has_attached_file :facepic,
:path => ":rails_root/public/system/:attachment/:id/:style/:filename",
:url => "/system/:attachment/:id/:style/:filename",
:styles => { :medium => "300x300>", :thumb => "100x100>" },
:default_url => "path to default image"
here default_url show image that you want if no image uploaded. For more detail you can go here http://rdoc.info/gems/paperclip/4.2.0/Paperclip/ClassMethods%3ahas_attached_file .
And for other error you can follow this link Paperclip::Errors::MissingRequiredValidatorError with Rails 4
Starting with Paperclip version 4.0, all attachments are required to include a content_type validation, a file_name validation, or to explicitly state that they're not going to have either.
Paperclip raises Paperclip::Errors::MissingRequiredValidatorError error if you do not do any of this.
In your case, you can add any of the following line to your Post model, after specifying has_attached_file :image
Option 1: Validate content type
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
-OR- another way
validates_attachment :image, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
-OR- yet another way
is to use regex for validating content type.
Option 2: Validate filename
validates_attachment_file_name :avatar, :matches => [/png\Z/, /jpe?g\Z/, /gif\Z/]
Option 3: Do not validate
If for some crazy reason (can be valid but I cannot think of one right now), you do not wish to add any content_type validation and allow people to spoof Content-Types and receive data you weren't expecting onto your server then add the following:
do_not_validate_attachment_file_type :image
Note:
Specify the MIME types as per your requirement within content_type/ matches options above. I have just given a few image MIME types for you to start with.
Reference:
Refer to Paperclip: Security Validations, if you still need to verify. :)
For details you can go to This question
I am sorry to say that my problem eventually was a bunch of things:
Had to add :facepic to the strong params
Had to add validations of content type to the model
Paperclip has a dependency... the file-command, which isn't shipped on Windows.
which can be downloaded here: http://sourceforge.net/projects/gnuwin32/?source=typ_redirect
After all three, it works like a charm!
Thank you all!
Paperclip 2.7
Ruby 1.8.7 Enterprise
Rails 3.1.0
Imagemagick 6.6
When i upload an image im my app, they are correctly processed by imagemagick and they are stored in conrrectly path. But, when i need to take this file to show, is not found.
Saving image:
Started POST "/p" for 177.16.57.105 at Sun Sep 23 23:39:16 -0300 2012
Processing by ProductsController#create as HTML
Parameters: {"commit"=>"Salvar", "authenticity_token"=>"EgBUGfKIIduS2lkl0mh5p27pT0vF0/P8HXO852KHMM8=", "utf8"=>"â", "product"=>{"photo"=>#>, "price"=>"", "name"=>"Brigadeiro de pistache", "product_type"=>"1", "featured"=>"0", "description"=>"Brigadeiro de pistache"}}
[32mCommand[0m :: convert '/tmp/stream20120923-19588-vw8u1s-020120923-19588-3lym39-0[0]' -resize "120x80>" '/tmp/stream20120923-19588-vw8u1s-020120923-19588-3lym39-020120923-19588-16ky3i8-0'
[paperclip] Saving attachments.
[paperclip] saving /home/brigaderiagourmand/apps_rails/site/public/system/photos/24/short/brigadeirocolorido.png
Redirected to http://brigaderiagourmand.com.br/p/24
Completed 302 Found in 257ms
And when i need take the file...
Started GET "/photos/original/missing.png" for 177.16.57.105 at Sun Sep 23 23:39:17 -0300 2012
ActionController::RoutingError (No route matches [GET] "/photos/original/missing.png"):
My model
class Product < ActiveRecord::Base
attr_accessible :name, :description, :price, :photo, :product_type, :featured
attr_accessor :photo_file_name
has_attached_file :photo, :styles => { :thumb => "50x50>", :medium => "280x180>", :large => "585x400>", :short => "120x80>", :original => "200,200>" }
TYPES = ["Belga", "Normal"]
end
Form views
= form_for #product, :html => {:multipart => true} do |f|
= f.file_field :photo
Show view
= image_tag #product.photo.url(:original)
Is the output from processing the image complete?
In your output paperclip only re-sizes to short (120x80>)
Your get request is trying to load the missing.jpg which is a default for image if the the requested couldn't be found. Take a look into /home/brigaderiagourmand/apps_rails/site/public/system/photos/24/ and see if there are the other re-sized photos.
There is a great screencast from Ryan Bates about paperclip
Hope this helps you
I use the following code to create Assets from the uploaded files:
def upload
uploader = User.find_by_id(params[:uploader_id])
params[:assets].each do |file|
new_asset = uploader.assets.build(:asset => file) # Here the error appears
new_asset.save
end
...
end
I noticed that when I upload non-image files, e.g. my.xlsx, I got the following error:
[paperclip] identify -format %wx%h "C:/temp/stream20110628-460-3vqjnd.xlsx[0]" 2>NUL
[paperclip] An error was received while processing:
#<Paperclip::NotIdentifiedByImageMagickError: C:/temp/stream20110628-460-3vqjnd.xlsx is
not recognized by the 'identify' command.>
(For image files everything works fine: a thumbnail is created, and there is no error.)
Is that because Paperclip tries to create a thumbnail from my.xlsx ?
What configuration will create thumbnails only for image files ?
Here is some relevant code:
class Asset < ActiveRecord::Base
belongs_to :uploader, :class_name => "User"
has_attached_file :asset, :styles => { :thumb => "80x80#" }
end
I used the following nice solution:
before_post_process :image?
def image?
(asset_content_type =~ SUPPORTED_IMAGES_REGEX).present?
end
where:
SUPPORTED_IMAGE_FORMATS = ["image/jpeg", "image/png", "image/gif", "image/bmp"]
SUPPORTED_IMAGES_REGEX = Regexp.new('\A(' + SUPPORTED_IMAGE_FORMATS.join('|') + ')\Z')
Change the has_attached_file line to read:
has_attached_file :asset, :styles => { :thumb=> "80x80#" }, :whiny_thumbnails => false
This will prevent it from raising an error when thumbnails are not created. Note though that it won't raise errors if one occurs when processing an image though.
I have a problem with the validation of the content type by the Paperclip plug-in:
image.rb (relevant extract)
has_attached_file :photo,
:styles => {:xlarge => "640x512>", :large => "350x280>", :medium => "180x144^",
:thumb => "100x80^", :original => "1280x1280>" },
:convert_options => {:xlarge => "-strip", :large => "-strip",
:medium => "-strip -gravity center -extent 180x144 +repage",
:thumb => "-strip -gravity center -extent 100x80 +repage"},
:default_style => :medium,
:url => "/system/:attachment/:id/:basename_:id_:style.:extension"
validates_attachment_presence :photo
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/png', 'image/gif', 'image/pjpeg', 'image/x-png', 'image/jpeg2000'], :message => 'Uploaded file is not an image'
I'm using nested forms, the image model is the child model of the property model.
During testing the validations of my form I come across some problems. I'm testing validations by uploading a PDF file where the model accepts only images.
output in my form view of: <%= #property.errors.inspect %>
#[#, #message="Uploaded file is not an image">],
"images.photo"=>[#, #message="C:/Users/Michael/AppData/Local/Temp/stream,4272,1.pdf is not recognized by the 'identify' command.">]}>, #base=#>
output in the view of the validation error(s) on the file upload input box:
C:/Users/Michael/AppData/Local/Temp/stream,4272,1.pdf is not recognized by the 'identify' command.
C:/Users/Michael/AppData/Local/Temp/stream,4272,1.pdf is not recognized by the 'identify' command.
C:/Users/Michael/AppData/Local/Temp/stream,4272,1.pdf is not recognized by the 'identify' command.
C:/Users/Michael/AppData/Local/Temp/stream,4272,1.pdf is not recognized by the 'identify' command.
C:/Users/Michael/AppData/Local/Temp/stream,4272,1.pdf is not recognized by the 'identify' command.
2 issues:
issue 1
The input field shows 5 times the same error, that is because I have 5 styles set up in the model. Question is, why does paperclip try to identify (and probably convert the pdf), when you would expect the validation to run first and return already an error before trying to identify and convert? Does Paperclip convert to all the styles before running validations? If yes, is there a way to switch the order of processing, first validation, then styles processing?
issue 2
How can I display the error message of the validation ('Uploaded file is not an image') next to the file upload input box instead of the erros now displayed (5 x the output of the identify command), the latter is of no use to the website user.
Thanks!
I have used
has_attached_file :photo, :whiny => false
and this seems to have helped the error messages. For the error messages, I was using
OBJECT.errors[:photo_content_type]
OBJECT.errors[:photo_file_size]