Save image from URL by paperclip - ruby-on-rails

Please suggest me a way to save an image from an URL by Paperclip.

In Paperclip 3.1.4 it's become even simpler.
def picture_from_url(url)
self.picture = URI.parse(url)
end
This is slightly better than open(url). Because with open(url) you're going to get "stringio.txt" as the filename. With the above you're going to get a proper name of the file based on the URL. i.e.
self.picture = URI.parse("http://something.com/blah/avatar.png")
self.picture_file_name # => "avatar.png"
self.picture_content_type # => "image/png"

Here is a simple way:
require "open-uri"
class User < ActiveRecord::Base
has_attached_file :picture
def picture_from_url(url)
self.picture = open(url)
end
end
Then simply :
user.picture_from_url "http://www.google.com/images/logos/ps_logo2.png"

It didn't work for me until I used "open" for parsed URI.
once I added "open" it worked!
def picture_from_url(url)
self.picture = URI.parse(url).open
end
My paperclip version is 4.2.1
Before open it wouldn't detect the content type right, because it wasn't a file. It would say image_content_type: "binary/octet-stream", and even if I override it with the right content type it wouldn't work.

First download the image with the curb gem to a TempFile and then simply assign the tempfile object and save your model.

Into official documentation is reported here https://github.com/thoughtbot/paperclip/wiki/Attachment-downloaded-from-a-URL
Anyway it seems not updated, because in last version of paperclip something has changed and this line of code is no more valid:
user.picture = URI.parse(url)
It raise an error, in particular this error is raised:
Paperclip::AdapterRegistry::NoHandlerError: No handler found for #<URI:: ...
The new correct syntax is this one:
url = "https://www.example.com/photo.jpeg"
user.picture = Paperclip.io_adapters.for(URI.parse(url).to_s, { hash_digest: Digest::MD5 })
Also we need to add these lines into config/initializers/paperclip.rb file:
Paperclip::DataUriAdapter.register
Paperclip::HttpUrlProxyAdapter.register
Tested this with paperclip version 5.3.0 and it works.

It may helpful to you. Here is the code using paperclip and image present in remote URL .
require 'rubygems'
require 'open-uri'
require 'paperclip'
model.update_attribute(:photo,open(website_vehicle.image_url))
In model
class Model < ActiveRecord::Base
has_attached_file :photo, :styles => { :small => "150x150>", :thumb => "75x75>" }
end

As those are old Answer's here's a newer one:
Add Image Remote URL to your desired Controller in the Database
$ rails generate migration AddImageRemoteUrlToYour_Controller image_remote_url:string
$ rake db:migrate
Edit your Model
attr_accessible :description, :image, :image_remote_url
.
.
.
def image_remote_url=(url_value)
self.image = URI.parse(url_value) unless url_value.blank?
super
end
*In Rails4 you have to add the attr_accessible in the Controller.
Update your form, if you allow other to upload an Image from a URL
<%= f.input :image_remote_url, label: "Enter a URL" %>

This is a hardcore method:
original_url = url.gsub(/\?.*$/, '')
filename = original_url.gsub(/^.*\//, '')
extension = File.extname(filename)
temp_images = Magick::Image.from_blob open(url).read
temp_images[0].write(url = "/tmp/#{Uuid.uuid}#{extension}")
self.file = File.open(url)
where Uuid.uuid just makes some random ID.

Related

Displaying an Image from Rails Seeds.rb [duplicate]

Please suggest me a way to save an image from an URL by Paperclip.
In Paperclip 3.1.4 it's become even simpler.
def picture_from_url(url)
self.picture = URI.parse(url)
end
This is slightly better than open(url). Because with open(url) you're going to get "stringio.txt" as the filename. With the above you're going to get a proper name of the file based on the URL. i.e.
self.picture = URI.parse("http://something.com/blah/avatar.png")
self.picture_file_name # => "avatar.png"
self.picture_content_type # => "image/png"
Here is a simple way:
require "open-uri"
class User < ActiveRecord::Base
has_attached_file :picture
def picture_from_url(url)
self.picture = open(url)
end
end
Then simply :
user.picture_from_url "http://www.google.com/images/logos/ps_logo2.png"
It didn't work for me until I used "open" for parsed URI.
once I added "open" it worked!
def picture_from_url(url)
self.picture = URI.parse(url).open
end
My paperclip version is 4.2.1
Before open it wouldn't detect the content type right, because it wasn't a file. It would say image_content_type: "binary/octet-stream", and even if I override it with the right content type it wouldn't work.
First download the image with the curb gem to a TempFile and then simply assign the tempfile object and save your model.
Into official documentation is reported here https://github.com/thoughtbot/paperclip/wiki/Attachment-downloaded-from-a-URL
Anyway it seems not updated, because in last version of paperclip something has changed and this line of code is no more valid:
user.picture = URI.parse(url)
It raise an error, in particular this error is raised:
Paperclip::AdapterRegistry::NoHandlerError: No handler found for #<URI:: ...
The new correct syntax is this one:
url = "https://www.example.com/photo.jpeg"
user.picture = Paperclip.io_adapters.for(URI.parse(url).to_s, { hash_digest: Digest::MD5 })
Also we need to add these lines into config/initializers/paperclip.rb file:
Paperclip::DataUriAdapter.register
Paperclip::HttpUrlProxyAdapter.register
Tested this with paperclip version 5.3.0 and it works.
It may helpful to you. Here is the code using paperclip and image present in remote URL .
require 'rubygems'
require 'open-uri'
require 'paperclip'
model.update_attribute(:photo,open(website_vehicle.image_url))
In model
class Model < ActiveRecord::Base
has_attached_file :photo, :styles => { :small => "150x150>", :thumb => "75x75>" }
end
As those are old Answer's here's a newer one:
Add Image Remote URL to your desired Controller in the Database
$ rails generate migration AddImageRemoteUrlToYour_Controller image_remote_url:string
$ rake db:migrate
Edit your Model
attr_accessible :description, :image, :image_remote_url
.
.
.
def image_remote_url=(url_value)
self.image = URI.parse(url_value) unless url_value.blank?
super
end
*In Rails4 you have to add the attr_accessible in the Controller.
Update your form, if you allow other to upload an Image from a URL
<%= f.input :image_remote_url, label: "Enter a URL" %>
This is a hardcore method:
original_url = url.gsub(/\?.*$/, '')
filename = original_url.gsub(/^.*\//, '')
extension = File.extname(filename)
temp_images = Magick::Image.from_blob open(url).read
temp_images[0].write(url = "/tmp/#{Uuid.uuid}#{extension}")
self.file = File.open(url)
where Uuid.uuid just makes some random ID.

Rails tag_id3v1 mp3

Rails 4.2 ap and taglib-ruby gem
I have tried a few approaches to tag my audio files using taglib-ruby.
I have tried as a carrierwave process, and now, I am trying to tag after_save.
My question, if I am doing a callback after_save:
def tag_id3v1(tags)
TagLib::MPEG::File.open(file.path) do |file|
tag = file.id3v1_tag(true)
tag.title = :title
file.save
end
end
what should my file path be? I have tried :file, :file_name, and the uploader version url, #{track.mp3.url}
I am trying to reopen the saved files and write the tags to the files. Does anyone have any hints on the best approach to do this?
Finally
TagLib::MPEG::File.open(file.file) do |file|
Always something like, "file.file". No matter the approach, that is what did the trick for me.
I ended up doing this in a carrierwave callback inside of a :version. Final code
version :mp3 do
process :convert => [:mp3]
def full_filename(for_file)
"#{super.chomp(File.extname(super))}.mp3"
end
after :store, :tag_id3v2
end
def tag_id3v2(for_file)
TagLib::MPEG::File.open(file.file) do |file|
tag = file.id3v2_tag(true)
tag.title = "#{model.title}"
file.save
end
end
(...)

Rails, before_create

Im rails beginner and I tried to add an carrierwave upload for image urls like shown in the episode #253 from railscast. So far all works good when i insert an normal link, for example
http:/.....g/dog-01.jpg
My problem is that I want to retrieve my images from a javascript plugin that gives a data:image out, how you can see here:
var url = canvas.toDataURL('image/png');
document.getElementById("canvascontent").value = url;
Also you can see that I insert the data:image to an input(#canvascontent).
<%= ff.text_field :remote_name_url, class => "canvascontent" %>
So now my problem, is that when I try to save simply the data:image from the text_field :remote_name_url, this dont works because it is encoded with base64.
The good thing is that Ruby has a Base64 encoder. To encode the data:image and save it in an image file (here png) I wrote a simply code, that I can execute from my console:
require 'base64'
data_url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB....."
png = Base64.decode64(data_url['data:image/png;base64,'.length .. -1])
File.open('testal', 'wb') { |f| f.write(png) }
So to come to the end. My problem is that I don't know how to achieve this with rails!
I know that there is an "code" for the model before_create, i tried something like that, but I didn't worked. I think because i have to safe the image first temporally!
before_create do
require 'base64'
self.remote_name_url = Base64.decode64(remote_name_url['data:image/png;base64,'.length .. -1])
end
class Painting < ActiveRecord::Base
belongs_to :treatment
attr_accessible :name, :image, :remote_name_url
mount_uploader :name, BildUploader
before_create do
require 'base64'
self.remote_name_url = Base64.decode64(remote_name_url['data:image/png;base64,'.length .. -1])
end
end
<
class TreatmentsController < ApplicationController
def create
#patient = Patient.find(params[:patient_id])
#treatment = #patient.treatments.create(params[:treatment])
redirect_to patient_path(#patient)
end
def destroy
#patient = Patient.find(params[:patient_id])
#treatment = #patient.treatments.find(params[:id])
#treatment.destroy
redirect_to patient_path(#patient)
end
end
This article from the Carrierwave wiki seems promising:
https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Upload-from-a-string-in-Rails-3
There's also the older technique of using Rack::Test::UploadedFile and a StringIO object, but that looks weirder in code that's not intended for the test environment.

paperclip renaming stringio.txt using instance_write

I am using omniauth-facebook and trying to get the profile picture to show up using paperclip. Here is the code I use to get the picture to my User model
def picture_from_url(url)
self.profile_pic =open(url)
end
However, it always saves as stringio.txt. So searching on this behavior I found out that paperclip allows for callbacks so I wrote the following method in the User model to rename the filename
def rename_profile_pic
self.profile_pic.instance_write :filename, "#{self.username}.jpg"
end
and passed it to the callback
before_post_process :rename_profile_pic
But this doesn't seem to help.
Any ideas how i can fix this ?
thanks
In case you haven't found the solution yet:
data = StringIO.new(file_data)
data.class.class_eval { attr_accessor :original_filename, :content_type }
data.content_type = content_type
data.original_filename = file_name
object.attachment = data
Convert your stringio.txt to file using this:
file = StringIO.new(obj)
file.original_filename = "#{self.username}.jpg"
and then assign your file to profile_pic
My solution for creating files from a string:
class FileIO < StringIO
def initialize(content:, filename:)
super(content)
#original_filename = filename
end
attr_reader :original_filename
end
FileIO.new(content: obj, filename: "#{username}.jpg")
This helped me solve the problem with the Carrierwave error when saving the file:
TypeError: no implicit conversion of nil into String

Paperclip how to change basename (filename)?

I am trying to change the basename (filename) of photos:
In my model I have:
attr_accessor :image_url, :basename
has_attached_file :image,
:styles => { :original => ["300x250>", :png], :small => ["165x138>", :png] },
:url => "/images/lille/:style/:id/:basename.:extension",
:path => ":rails_root/public/images/lille/:style/:id/:basename.:extension"
before_save :basename
private
def basename
self.basename = "HALLLO"
end
But the filename is not changed at all.
If you are assigning the file directly you can do this:
photo.image = the_file
photo.image.instance_write(:file_name, "the_desired_filename.png")
photo.save
Im doing this to strip whitespaces:
before_post_process :transliterate_file_name
private
def transliterate_file_name
self.instance_variable_get(:#_paperclip_attachments).keys.each do |attachment|
attachment_file_name = (attachment.to_s + '_file_name').to_sym
if self.send(attachment_file_name)
self.send(attachment).instance_write(:file_name, self.send(attachment_file_name).gsub(/ /,'_'))
end
end
end
I hope this will help you.
edit:
In your example:
def basename
self.image_file_name = "foobar"
end
Should do the job. (but might rename the method ;) )
Paperclip now allows you to pass in a FilenameCleaner object when setting up has_attached_file.
Your FilenameCleaner object must respond to call with filename as the only parameter. The default FilenameCleaner removes invalid characters if restricted_characters option is supplied when setting up has_attached_file.
So it'll look something like:
has_attached_file :image,
filename_cleaner: MyRandomFilenameCleaner.new
styles: { thumbnail: '100x100' }
And MyRandomFilenameCleaner will be:
class MyRandomFilenameCleaner
def call(filename)
extension = File.extname(filename).downcase
"#{Digest::SHA1.hexdigest(filename + Time.current.to_s).slice(0..10)}#{extension}"
end
end
You could get away with passing in a class that has a self.call method rather than an object but this conforms to Paperclip's documentation in Attachment.rb.
I wanted to avoid having to add a before_create callback to every model with an attachment. I had a look at the source and at the time of this writing it looked sth like:
module Paperclip
class Attachment
...
def assign_file_information
instance_write(:file_name, cleanup_filename(#file.original_filename))
instance_write(:content_type, #file.content_type.to_s.strip)
instance_write(:file_size, #file.size)
end
So you could just patch cleanup_filename.
config/initializers/paperclip.rb
module Paperclip
class Attachment
def cleanup_filename(filename)
"HALLLO"
end
end
end

Resources