Paperclip save remote images without extension - ruby-on-rails

Here I have Controller
require 'open-uri'
user = User.new
url = "some_remote_image.jpg" #remote image WITH extension
user.image = open(url)
user.save
Model
has_attached_file :image,
:styles => { :thumb => "25x25>", :large => "1000x1000>" },
:path => ":rails_root/images/users/:id/:style/:hash.:extension",
:url => "/images/users/:id/:style/:hash.:extension",
:hash_secret => "hash string"
This work, but images stores without extension, for ex. "some_remote_image."
If uploading images by post form everything uploading WITH extension.
I'm confused.

I solved it by updating Paperclip to last github version and set image like this instead of user.image = open(url)
user.image = URI.parse(url)

In case if someone wants reverse thing - add extension to no extension files
def besfore_save
tempfile = data.queued_for_write[:original]
unless tempfile.nil?
extension = File.extname(tempfile.original_filename)
if !extension || extension == ''
mime = tempfile.content_type
ext = Rack::Mime::MIME_TYPES.invert[mime]
self.data.instance_write :file_name, "#{tempfile.original_filename}#{ext}"
end
end
true
end

Related

Generate Thumbnail From pdf in rails paperclip

How can I generate the first page of a pdf as a thumbnail in paperclip?
I tried a lot but it's not working
has_attached_file :book_url, :styles => {
:thumb => "100x100#",
:small => "150x150>",
:medium => "200x200" }
This is giving the name of the pdf as a link but it's not giving the first page of the pdf
<%= link_to 'My PDF', #book.book_url.url %>
Tadas' answer is right, but for those who need more context, you can do something like this: The model below only creates thumbnails for certain kinds of files (e.g. it doesn't make thumbnails of audio files), but does make thumbnails for pdfs, image files, and video files:
class Record < ActiveRecord::Base
print self # for logging on heroku
belongs_to :user
# Ensure user has provided the required fields
validates :title, presence: true
validates :file_upload, presence: true
validates :description, presence: true
# Use the has_attached_file method to add a file_upload property to the Record
# class.
has_attached_file :file_upload,
# In order to determine the styles of the image we want to save
# e.g. a small style copy of the image, plus a large style copy
# of the image, call the check_file_type method
styles: lambda { |a| a.instance.check_file_type },
processors: lambda {
|a| a.is_video? ? [ :ffmpeg ] : [ :thumbnail ]
}
# Validate that we accept the type of file the user is uploading
# by explicitly listing the mimetypes we are willing to accept
validates_attachment_content_type :file_upload,
:content_type => [
"video/mp4",
"video/quicktime",
"image/jpg",
"image/jpeg",
"image/png",
"image/gif",
"application/pdf",
"audio/mpeg",
"audio/x-mpeg",
"audio/mp3",
"audio/x-mp3",
"file/txt",
"text/plain",
"application/doc",
"application/msword",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-powerpoint"
],
:message => "Sorry! We do not accept the attached file type"
# Before applying the Imagemagick post processing to this record
# check to see if we indeed wish to process the file. In the case
# of audio files, we don't want to apply post processing
before_post_process :apply_post_processing?
# Helper method that uses the =~ regex method to see if
# the current file_upload has a content_type
# attribute that contains the string "image" / "video", or "audio"
def is_image?
self.file_upload.content_type =~ %r(image)
end
def is_video?
self.file_upload.content_type =~ %r(video)
end
def is_audio?
self.file_upload.content_type =~ /\Aaudio\/.*\Z/
end
def is_plain_text?
self.file_upload_file_name =~ %r{\.(txt)$}i
end
def is_excel?
self.file_upload_file_name =~ %r{\.(xls|xlt|xla|xlsx|xlsm|xltx|xltm|xlsb|xlam|csv|tsv)$}i
end
def is_word_document?
self.file_upload_file_name =~ %r{\.(docx|doc|dotx|docm|dotm)$}i
end
def is_powerpoint?
self.file_upload_file_name =~ %r{\.(pptx|ppt|potx|pot|ppsx|pps|pptm|potm|ppsm|ppam)$}i
end
def is_pdf?
self.file_upload_file_name =~ %r{\.(pdf)$}i
end
def has_default_image?
is_audio?
is_plain_text?
is_excel?
is_word_document?
end
# If the uploaded content type is an audio file,
# return false so that we'll skip audio post processing
def apply_post_processing?
if self.has_default_image?
return false
else
return true
end
end
# Method to be called in order to determine what styles we should
# save of a file.
def check_file_type
if self.is_image?
{
:thumb => "200x200>",
:medium => "500x500>"
}
elsif self.is_pdf?
{
:thumb => ["200x200>", :png],
:medium => ["500x500>", :png]
}
elsif self.is_video?
{
:thumb => {
:geometry => "200x200>",
:format => 'jpg',
:time => 0
},
:medium => {
:geometry => "500x500>",
:format => 'jpg',
:time => 0
}
}
elsif self.is_audio?
{
:audio => {
:format => "mp3"
}
}
else
{}
end
end
end
I think I once got it working by enforcing a file type, e.g.
:thumb => ["100x100#", :png]
of course it's not ideal, because it enforces this filetype for every upload
Thanks a million to #duhaime for his beautiful answer.
Since this is the most complete source of information I found to have PDF attached, I'd like to document it further:
Requirements:
imagemagick
ghostscript (I forgot about this one)
(optional) ffmpeg if you want to handle video files
Also I replaced has_default_image? and apply_post_processing? with the single:
def can_thumbnail?
self.check_file_type.try(:{], :thumb).present?
end
Finally I created a method for the not-thumbable attachments:
def thumb
return self.file.url(:thumb) if self.can_thumbnail?
if self.is_video?
'/thumb/video.png'
else
'/thumb/default.png'
end
end
But thanks again #duhaime

Generated Picture Filesize Upload for RSS

I upload a picture via paperclip (in rails). This picture will appear in the rss feed. For the RSS feed, I need to fill the field length which tells the client the file length I guess.
It would be easy for the attached file itself, because the there is a column file_size, but what if the picture is post-process and I want to include this picture, how do I get the file size?
Code:
pic.rb
class Pic < ActiveRecord::Base
has_attached_file :image,
:styles => {
:mail => "780x540>",
:medium => "260x180>",
:thumb => "130x90>",
},
:storage => :s3
end
rss.rb
xml.instruct! :xml, version: "1.0"
xml.rss version: "2.0" do
xml.channel do
#ps.each do |p|
xml.item do
xml.title p.title
xml.description p.description.truncate(250)
xml.pubDate p.starts_at.to_s(:rfc822)
xml.link p.uri_name
xml.guid p.uri_name
xml.enclosure url: p.pic(:medium), type: "image/jpeg", length: ??
end
end
end
end
Should be easy, but..
Found the solution:
Because it's stored on s3, I can get the information via http..
in pic.rb
def content_length(size)
parts = URI.parse image.url(size)
Net::HTTP.start(parts.host, parts.port) do |http|
response = http.request_head parts.path
file_size = response['content-length']
end
end

Paperclip on S3 is changing file extensions from a url

I wrote a rake task that downloads an image from wikipedia given a celebrity name, but for some reason when storing on S3 the file extension is either being dropped or changed to .txt
The file otherwise is correct.
Any ideas?
From my celeb model:
has_attached_file :pic,
:styles => { :medium => "300x300>", :thumb => "100x100>" },
:default_style => :medium,
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:path => "/:style/:img_name.:extension"
From my rake task:
desc "Update celeb pics from wiki"
task :update_celeb_pics => [:environment] do
include ApplicationHelper
Celeb.all.each do |celeb|
if !celeb.name.start_with?("(")
puts celeb.name
celeb.pic = open(getImage(celeb.name))
celeb.save
end
end
end
the getImage method is a helper that returns a string
require 'open-uri'
require 'uri'
module ApplicationHelper
def getInfo(name)
Nokogiri::XML(open(URI.escape("http://en.wikipedia.org/w/api.php?action=opensearch&search=#{name}&limit=1&namespace=0&format=xml")))
end
def nokoPage(name)
Nokogiri::XML(open(getURL(name)))
end
def getImage(name)
"http:" + nokoPage(name).css("table img")[0].attribute("src").value if !nokoPage(name).css("table img").empty?
end
def getDescription(name)
getInfo(name).css("Description").text
end
def getURL(name)
getInfo(name).css("Url").text
end
def getBday(name)
bday = nokoPage(name).css("span.bday")
return Date.parse(bday[0].text) if !bday.empty?
return Date.today
end
def getDday(name)
dday = nokoPage(name).css("span.dday")
return Date.parse(dday[0].text) if !dday.empty?
end
end
This is because
self.pic = open("http://something.com/bla/image.png")
is not the best solution here. Just yesterday, i got a Pull Request merged into Paperclip that lets you do this
self.pic = URI.parse(getImage(name))
This will ensure that your pic's content type matches the downloaded file, pic's filename is set to the name of the file downloaded.
The reason you get txt extension is because open returns a StringIO object which infact names the filename as "stringio.txt". Your filename is probably changed by the s3 code but the extension remains as '.txt'
I suggest you link your Gemfile to paperclip's github repo, run bundle and try again.
Cheers,
Aditya

File upload Base64 encoded string in PaperClip using Rails

I have at base64 encoded string of a image file. I need to save it using Paper Clip
My Controller code is
#driver = User.find(6)
encoded_file = Base64.encode64(File.open('/pjt_path/public/test.jpg').read)
decoded_file = Base64.decode64(encoded_file)
#driver.profile_pic = StringIO.open(decoded_file)
#driver.save
In my user model
has_attached_file :profile_pic, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => '/icon.jpg'
Currently the file is saved as a text file(stringio.txt). But when I change the extension to JPG I can view it as image. How can I name the image correctly using StringIO.
I am having rails 3.2, ruby 1.9.2, paperclip 3.0.3
I fixed the issue by using
encoded_file = Base64.encode64(File.open('/pjt_path/public/test.jpg').read)
decoded_file = Base64.decode64(params[:encoded_image])
begin
file = Tempfile.new(['test', '.jpg'])
file.binmode
file.write decoded_file
file.close
#user.profile_pic = file
if #user.save
render :json => {:message => "Successfully uploaded the profile picture."}
else
render :json => {:message => "Failed to upload image"}
end
ensure
file.unlink
end
Try setting the :path/:url option of has_attached_file and explicitly overriding the extension:
http://rdoc.info/gems/paperclip/Paperclip/ClassMethods#has_attached_file-instance_method
respectively
http://rdoc.info/gems/paperclip/Paperclip/Storage/Filesystem

Rails 3 - Tempfile Path?

I have the following:
attachments.each do |a|
Rails.logger.info a.filename
tempfile = Tempfile.new("#{a.filename}", "#{Rails.root.to_s}/tmp/")
Rails.logger.info tempfile.path
end
Where attachments is from paperclip.
Here's the output:
billgates.jpg
/Users/bhellman/Sites/cline/tmp/billgates.jpg20101204-17402-of0u9o-0
Why is the file name getting 20101204-17402-of0u9o-0 appended to at the end? That's breaking everything with paperclip etc. Anyone seen this before? For the life of I have no idea what's doing it?
Thanks
UPDATE
Paperclip: Paperclip on github
a is the attachment file
tempfile = Tempfile.new("#{a.filename}", "#{Rails.root.to_s}/tmp/")
tempfile << a.body
tempfile.puts
attachments.build(
:attachment => File.open(tempfile.path)
)
best make sure your tempfile has the correct extension, saving you to trying and change it after:
file = Tempfile.new(['hello', '.jpg'])
file.path # => something like: "/tmp/hello2843-8392-92849382--0.jpg"
more here: http://apidock.com/ruby/v1_9_3_125/Tempfile/new/class
The first argument for Tempfile.new is just a basename. To make sure each Tempfile is unique the characters are appended to the end of the file.
You should use Paperclip's API for this:
tempfiles = []
attachments.each do |a|
# use Attachment#to_file to get a :filesystem => file, :s3 => tempfile
tempfiles << a.to_file
end
tempfiles.each do |tf|
Rails.logger.debug tf.filename
end
attachment = attachments.build(
:attachment => File.open(tempfile.path)
)
# change the displayed file name stored in the db record here
attachment.attachment_file_name = a.filename # or whatever else you like
attachment.save!
The best way I found to deal with this was to specify the file extension in the Paperclip attribute. For example:
has_attached_file :picture,
:url => "/system/:hash.jpg",
:hash_secret => "long_secret_string",
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml"
Note that the :url is declared as '.jpg' rather than the traditional .:extension.
Good luck!

Resources