How to set all attributes to UploadedFile in Rails 4 - ruby-on-rails

I've an API and I send a image from Angular Client in Base64, I've the next code for my method create:
if params[:profile][:picture]
picture_params = params[:profile][:picture]
#Create new Temporal File
temp_file = Tempfile.new("file_to_upload")
temp_file.binmode
temp_file.write(Base64.decode64(picture_params["body"]))
#Create a new uploaded file
uploaded_file = ActionDispatch::Http::UploadedFile.new(
:tempfile => temp_file,
:original_filename => picture_params[:name])
#After replace picture with the new uploaded file
params[:profile][:picture] = uploaded_file
Rails.logger.info "#{params[:profile]}"
end
#profile = #current_user.build_profile(profile_params)
if #profile.save
render "api/v1/profiles/show"
else
errors_array!(#profile.errors.full_messages, :unprocessable_entity)
end
After when I print my params the information is nil
"picture"=>#<ActionDispatch::Http::UploadedFile:0x007f872daac5b0 #tempfile=#<Tempfile:/var/folders/nx/30024wp17ggfgw542lyzs4zw0000gn/T/file_to_upload20160225-14952-by947r>, #original_filename=nil, #content_type=nil, #headers=nil>}
And after when try to create the profile I've the next error, I think that is for the previous problem
NoMethodError (undefined method `gsub' for nil:NilClass):
app/controllers/api/v1/profiles_controller.rb:39:in `create'
I use the paperclip gem for upload files in Rails 4.2.5.1

Thanks for watching, but Have a solution, I changed my method:
def set_selfies(selfie_params)
picture_params = selfie_params
encoded_picture = picture_params[:body]
content_type = picture_params[:content_type]
image = Paperclip.io_adapters.for("#{encoded_picture}")
image.original_filename = picture_params[:name]
image
end
I Read this Blog:
And That's all, works for me, Thanks :D

Related

Rails 7 RestClient::Not found in find_each loop updating avatar from Microsoft Graph

I'm trying to attach all pictures from the Microsoft Graph to my new Rails application using active storage and the rest-client gem.
It works for a single user I do it like this:
User.find_by_email("user.email#domain.com).avatar.attach io:StringIO.open(image.to_blob), filename: "avatar.jpg", content_type: metadata["mimeType"], identify: false
But in a batch loop, it doesn't work.
class RestController < ApplicationController
require 'rest-client'
def sync_azure_picture
#token = RestController.get_azure_token
User.find_each do |currentUser|
request_url = 'https://graph.microsoft.com/v1.0/users/'+currentUser[:id_azure]+'/photo/$value'
puts request_url
resp = RestClient.get(request_url,'Authorization' => #token)
image = MiniMagick::Image.read(resp.body)
metadata = image.data
currentUser.avatar.attach io:StringIO.open(image.to_blob), filename: "avatar.jpg", content_type: metadata["mimeType"], identify: false
end
end
end`
The error i'm getting is
RestClient::NotFound
Probably not all users have attachments? You can log errors and then check these urls
User.find_each do |user|
# ...
rescue RestClient::NotFound => e
Rails.logger.error("#{request_url}:")
Rails.logger.error(e)
end

Rails saving a pdf to Amazon S3

I have a Rails 3.2 app that uses gem 'wicked_pdf', and gem 'combine_pdf'.
They both work and I can create PDFs which get emailed.
But, I have run into a situation where the email would be too big.
So, I'm trying to save the created pdf to Amazon S3. The app already has the gem 'aws-sdk'.
This is my code:
def self.saveallpdf
#costprojects = Costproject.where("client_id = 2")
pdf = CombinePDF.new
#costprojects.each do |costproject|
#costproject = costproject
controller = CostprojectsController.new
controller.instance_variable_set(:"#costproject", #costproject)
pdf2 = controller.render_to_string(pdf: "Captital Projects.pdf",
template: "costprojects/viewproject",
encoding: "UTF-8")
pdf << CombinePDF.parse(pdf2)
end
#s3 = AWS::S3.new
#bucket = #s3.buckets['ndeavor3-pdf']
#obj = #bucket.objects['filename'].write(pdf, acl: :public_read)
end
The error I'm getting is:
:data must be provided as a String, Pathname, File, or an object that responds to #read and #eof?
/app/vendor/bundle/ruby/1.9.1/gems/aws-sdk-1.8.3.1/lib/aws/s3/data_options.rb:125:in `validate_data!'
/app/vendor/bundle/ruby/1.9.1/gems/aws-sdk-1.8.3.1/lib/aws/s3/data_options.rb:32:in `compute_write_options'
/app/vendor/bundle/ruby/1.9.1/gems/aws-sdk-1.8.3.1/lib/aws/s3/s3_object.rb:594:in `write'
/app/app/models/costproject.rb:167:in `saveallpdf
'
I guess was-sdk doesn't like the "pdf" as the file??
PS - I can email the "pdf" - if it was smaller in size.
Thanks for your help!
At this point in time:
#obj = #bucket.objects['filename'].write(pdf, acl: :public_read)
pdf is a CombinePDF object and not a File, String, or Pathname
pdf.to_s might work, or you will have to create a new file from the CombinePDF object
File.new(CombinePDF) # pseduo code only

Rails + Prawn_rails: How do I add an image to my PDF?

I'm using this gem to use Prawn to create a PDF: https://github.com/Whoops/prawn-rails
However, I can't seem to figure out how to add an image. I've tried pdf.image "path/to/img.jpg but it would say the file is not a recognized format.
I've also looked into this on page 101: http://prawn.majesticseacreature.com/manual.pdf , but it doesn't work.
This is happening in the views:
prawn_document() do |pdf|
pdf.image "#{Rails.root}/public/logo.gif"
end
This throws:
Prawn::Errors::UnsupportedImageType at /admin/purchases/6188.pdf
image file is an unrecognised format
Same happens for a .jpg image
I would do something like this.
gem 'prawn'
bundle install
In your controller.
def controller_method
pdf = Prawn::Document.new
begin
pdf_file_path = "#{Rails.root}/public/output"
full_doc = "#{Rails.root}/public/something.png"
pdf.image full_doc
pdf.start_new_page
pdf.render_file pdf_file_path
rescue Prawn::Errors::UnsupportedImageType
flash[:notice] = "Image unsupported"
redirect_to '/handle'
end
end
Adding an image is easy enough.
def download
#document = Document.find(params[:id])
tmp_file = Tempfile.new(Digest::MD5.hexdigest(rand(12).to_s))
pdf = Prawn::Document.generate(tmp_file.path, :margin => 0, :page_size => "A4", :skip_page_creation => true) do |posting|
posting.start_new_page
posting.image #document.user.logo.path
send_data posting.render, :filename => "whatever.pdf", :type => "application/pdf"
end
end
Obviously #document.user.logo.path could be a literal path, that's just a Paperclip attachment in this case.
UPDATE
If it's a literal path you might need to do something like this:
require "open-uri"
def download
...
posting.image File.open("/path/to/image.jpg")
...
end
It seems the latest prawn (version 1.0.0) has changed. You'll get
undefined method `image=' for #<Prawn::Document
if you try and apply something to pdf.image.
This worked for me:
img = "#{Rails.root}/public/my_lovely_image.png"
Prawn::Document.new(background: img)

Get mosaic-like screenshot using IMGKit

Here I want to take a screenshot of an external url, and I use IMGkit with CarrierWave.
#Class Micropost
after_create :take_snapshot
def take_snapshot
file = Tempfile.new(["template_#{self.id.to_s}", 'jpg'], 'tmp', :encoding => 'ascii-8bit')
file.write(IMGKit.new(self.external_url).to_jpg)
file.flush
self.snapshot = file
self.save
file.unlink
end
and the screenshot get generated is.....
So whats wrong with it?

Downloading and zipping files that were uploaded to S3 with CarrierWave

I have a small Rails 3.2.1 app that uses CarrierWave 0.5.8 for file uploads to S3 (using Fog)
I want users to be able to select some images that they'd like to download, then zip them up and send them a zip. Here is what I've come up with:
def generate_zip
#A collection of Photo objects. The Photo object has a PhotoUploader mounted.
photos = Photo.all
tmp_filename = "#{Rails.root}/tmp/" << Time.now.strftime('%Y-%m-%d-%H%M%S-%N').to_s << ".zip"
zip = Zip::ZipFile.open(tmp_filename, Zip::ZipFile::CREATE)
zip.close
photos.each do |photo|
file_to_add = photo.photo.file
zip = Zip::ZipFile.open(tmp_filename)
zip.add("tmp/", file_to_add.path)
zip.close
end
#do the rest.. like send zip or upload file and e-mail link
end
This doesn't work because photo.photo.file returns an instance of CarrierWave::Storage::Fog::File instead of a regular file.
EDIT: The error this leads to:
Errno::ENOENT: No such file or directory - uploads/photos/name.jpg
I also tried the following:
tmp_filename = "#{Rails.root}/tmp/" << Time.now.strftime('%Y-%m-%d-%H%M%S-%N').to_s << ".zip"
zip = Zip::ZipFile.open(tmp_filename, Zip::ZipFile::CREATE)
zip.close
photos.each do |photo|
processed_uri = URI.parse(URI.escape(URI.unescape(photo.photo.file.authenticated_url)).gsub("[", "%5B").gsub("]", "%5D"))
file_to_add = CarrierWave::Uploader::Download::RemoteFile.new(processed_uri)
zip = Zip::ZipFile.open(tmp_filename)
zip.add("tmp/", file_to_add.path)
zip.close
end
But this gives me a 403. Some help would be greatly appreciated.. It probably is not that hard I'm just Doing it Wrong™
I've managed to solve the problem with help from #ffoeg
The solution offered by #ffoeg didn't work quite so well for me since I was dealing with zip files > 500 MB which caused me problems on Heroku. I've therefor moved the zipping to a background process using resque:
app/workers/photo_zipper.rb:
require 'zip/zip'
require 'zip/zipfilesystem'
require 'open-uri'
class PhotoZipper
#queue = :photozip_queue
#I pass
def self.perform(id_of_object_with_images, id_of_user_to_be_notified)
user_mail = User.where(:id => id_of_user_to_be_notified).pluck(:email)
export = PhotoZipper.generate_zip(id_of_object_with_images, id_of_user_to_be_notified)
Notifications.zip_ready(export.archive_url, user_mail).deliver
end
# Zipfile generator
def self.generate_zip(id_of_object_with_images, id_of_user_to_be_notified)
object = ObjectWithImages.find(id_of_object_with_images)
photos = object.images
# base temp dir
temp_dir = Dir.mktmpdir
# path for zip we are about to create, I find that ruby zip needs to write to a real file
# This assumes the ObjectWithImages object has an attribute title which is a string.
zip_path = File.join(temp_dir, "#{object.title}_#{Date.today.to_s}.zip")
Zip::ZipOutputStream.open(zip_path) do |zos|
photos.each do |photo|
path = photo.photo.path
zos.put_next_entry(path)
zos.write photo.photo.file.read
end
end
#Find the user that made the request
user = User.find(id_of_user_to_be_notified)
#Create an export object associated to the user
export = user.exports.build
#Associate the created zip to the export
export.archive = File.open(zip_path)
#Upload the archive
export.save!
#return the export object
export
ensure
# clean up the tempdir now!
FileUtils.rm_rf temp_dir if temp_dir
end
end
app/controllers/photos_controller.rb:
format.zip do
#pick the last ObjectWithImages.. ofcourse you should include your own logic here
id_of_object_with_images = ObjectWithImages.last.id
#enqueue the Photozipper task
Resque.enqueue(PhotoZipper, id_of_object_with_images, current_user.id)
#don't keep the user waiting and flash a message with information about what's happening behind the scenes
redirect_to some_path, :notice => "Your zip is being created, you will receive an e-mail once this process is complete"
end
Many thanks to #ffoeg for helping me out. If your zips are smaller you could try #ffoeg's solution.
Here is my take. There could be typos but I think this is the gist of it :)
# action method, stream the zip
def download_photos_as_zip # silly name but you get the idea
generate_zip do |zipname, zip_path|
File.open(zip_path, 'rb') do |zf|
# you may need to set these to get the file to stream (if you care about that)
# self.last_modified
# self.etag
# self.response.headers['Content-Length']
self.response.headers['Content-Type'] = "application/zip"
self.response.headers['Content-Disposition'] = "attachment; filename=#{zipname}"
self.response.body = Enumerator.new do |out| # Enumerator is ruby 1.9
while !zf.eof? do
out << zf.read(4096)
end
end
end
end
end
# Zipfile generator
def generate_zip(&block)
photos = Photo.all
# base temp dir
temp_dir = Dir.mktempdir
# path for zip we are about to create, I find that ruby zip needs to write to a real file
zip_path = File.join(temp_dir, 'export.zip')
Zip::ZipFile::open(zip_path, true) do |zipfile|
photos.each do |photo|
zipfile.get_output_stream(photo.photo.identifier) do |io|
io.write photo.photo.file.read
end
end
end
# yield the zipfile to the action
block.call 'export.zip', zip_path
ensure
# clean up the tempdir now!
FileUtils.rm_rf temp_dir if temp_dir
end

Resources