I'm trying to write a method to store an image from a given url, inside a ruby worker. It comes along my Rails app in which I display the object image. Here is what I've come up with:
#message = Message.create!
my_uploader = PhotoUploader.new
photo = open(image_url)
#message[:photo] = my_uploader.store!(photo)
#message[:photo] = my_uploader.filename
#message.save!
the PhotoUploader:
def store_dir
Rails.env.production? ? (primary_folder = "production") : (primary_folder = "test")
"#{primary_folder}/media/#{model.id}"
end
the Message class:
class Message < ActiveRecord::Base
attr_accessible :content, :photo, :user_id
mount_uploader :photo, PhotoUploader
end
The model.id returns an error in the storage path. The model is nil even after saving it, and the file is stored in #{primary_folder}/media
I think it's that you're not calling store! from the model, which is why model.id doesn't work, because model is nil
This will probably do it for you:
#message = Message.create!
photo = open(image_url)
#message.photo = PhotoUploader.new
#message.photo.store!(photo)
#message.photo = #message.photo.filename
#message.save!
I tried this out in the rails console, and #message[:photo].store!(photo) gave the same error, but #message.photo.store!(photo) worked.
Related
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.
I have the following code inside my controller:
array = Contact.select(:name).distinct
The idea is that this would create an array of all Contact models with a unique :name attribute. However, it's throwing this error:
NoMethodError (private method 'select' called for Contact:Class)
What's the misunderstanding here? For what it's worth, the method calling this line of code is not defined in the controller as private.
EDIT:
Here's the actual code:
Controller
class FluidsurveysController < ApplicationController
def index
end
def import_contacts
#survey_provider = FluidsurveysProviders::SurveyProvider.new()
#current_month = Time.new.strftime("%B%Y%d")
fs_contact_list_array = csv_to_array(params[:file].tempfile)
#fs_contacts_array = []
fs_contact_list_array.each do |hash|
#fs_contacts_array << Contact.new(hash)
end
array = Contact.select(:name).distinct
end
end
Model
class Contact
include ActiveModel::Model
attr_reader :client_id, :client_name, :branch_id, :branch, :short_name, :unit_id, :membership_id,
:first_name, :last_name, :date_of_birth, :change_date_time, :membership_type,
:home_phone, :email_address, :anniversary_years
def initialize(fs_contact_hash = {})
#client_id = fs_contact_hash.fetch('ClientID')
#client_name = fs_contact_hash.fetch('ClientName')
#branch_id = fs_contact_hash.fetch('branchID1')
#branch = fs_contact_hash.fetch('branch')
#name = fs_contact_hash.fetch('ShortName')
#unit_id = fs_contact_hash.fetch('UnitID')
#membership_id = fs_contact_hash.fetch('MemberID')
#first_name = fs_contact_hash.fetch('FirstName')
#last_name = fs_contact_hash.fetch('LastName')
#date_of_birth = fs_contact_hash.fetch('DateOfBirth')
#change_date_time = fs_contact_hash.fetch('ChangeDateTime')
#membership_type = fs_contact_hash.fetch('MembershipType')
#home_phone = fs_contact_hash.fetch('HomePhone')
#email_address = fs_contact_hash.fetch('EMail1')
#anniversary_years = fs_contact_hash.fetch('Years')
end
end
Based on your error message I am pretty sure your model is not an ActiveRecord Object.
If you want to make use of ActiveRecord#select, define your model like this.
class Contact < ActiveRecord::Base
Also you need to define your attributes in a database instead of via attr_reader to access them through ActiveRecord. See http://guides.rubyonrails.org/getting_started.html#running-a-migration
You seem to be using an older version of Rails, specifically version 2.3.whatever. There, the select method is indeed private on the ActiveRecord model classes (as it is inherited from the Kernel module which is part of every Ruby object and serves a wholly different purpose) and thus isn't intended to be used like it is done in Rails 3 and Rails 4.
In Rails 2.3, you can achieve similar results using this syntax:
Contact.all(:select => "DISTINCT name")
This will return an array of Contacts which have only the name attribute set.
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.
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
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.