Accept an image via Rails 5 API and Active Storage - ruby-on-rails-5

I am trying to send images to my Rails app and then store them via Active Storage.
I tried Base64 and direct upload and researched for hours but nothing really works.
Can somebody point me to a good way?
My last attempt was to use Base64 like so:
def attach_preview
page = Page.first
content = JSON.parse(request.body.read)
decoded_data = Base64.decode64(content["file_content"].force_encoding("UTF-8"))
begin
file = Tempfile.new('test')
file.write decoded_data
#page.thumbnail = file
filename = "foooo"
page.thumbnail.attach(io: File.read(file), filename: filename)
if page.save
render :json => {:message => "Successfully uploaded the profile picture."}
else
render :json => {:message => "Failed to upload image"}
end
ensure
file.close
file.unlink
end
end
But this results in a "\xAB" from ASCII-8BIT to UTF-8 error.
Dont really care if its Base64 or something else, I just need a way :-)

This works, I use IO directly since ActiveStorage needs it anyway.
def attach_thumbnail
content = JSON.parse(request.body.read.force_encoding("UTF-8"))
decoded_data = Base64.decode64(content["file_content"])
io = StringIO.new
io.puts(decoded_data)
io.rewind
#page.thumbnail.attach(io: io, filename: 'base.png')
#page.save
render json: {
success: #page.thumbnail.attached?,
thumbnail_url: url_for(#page.thumbnail),
page: #page
}
end

Related

Rails 3.2 SSRS and SavonRD

I'm integrating my Rails 3.2 app with SSRS for reporting using Savonrb to do the Soap call to the SSRS web service. Everything is finally working and I can successfully make the following calls:
LoadReport
SetExecutionParameters
Render
The render call takes a format parameter (in my case PDF) and returns an XML response. I thought the call would result in the report being rendered in a pdf, but it doesn't. What do I need to do with the response object to render the report?
code below:
response = #client.call(:load_report, message: {report: "/path/to/report"} )
response = #client.call(:set_execution_parameters, message: { "Parameters" => param1} )
response = #client.call(:render, message: {"Format" => "PDF"})
Thanks!
The answer is that I need to take the xml string that was returned from the render call and decode it to Base64, write it to a file, and then user send_file to stream the file to the browser. This works now, code below:
response = #newClient.call(:render, message: {"Format" => "PDF"})
#results = response.to_hash
#report = #results[:render_response][:result]
#extension = #results[:render_response][:extension]
#mime_type = #results[:render_response][:mime_type]
#report_name = "MyReportName.pdf" # this should be dynamically generated from a param passed in the call to run_report
File.open(#report_name, "wb+") do |f|
f.puts Base64.decode64(#report)
end
#file = File.open(#report_name, 'r')
send_file #file, :filename => #report_name, :type => "application/pdf; charset=utf-8", :disposition => "attachment"

Paperclip and Phusion Passenger NoHandlerError

I followed this guide to get drag and drop file uploads through AJAX: http://dannemanne.com/posts/drag-n-drop_upload_that_works_with_ror_and_paperclip
Everything was working fine on my development environment with WebBrick but if I deploy to PhusionPassenger then I get:
Paperclip::AdapterRegistry::NoHandlerError (No handler found for #<PhusionPassenger::Utils::RewindableInput:0x000000041aef38 #io=#<PhusionPassen...
I'm using this in my controller:
before_filter :parse_raw_upload, :only => :bulk_submissions
def bulk_submissions
...
#submission = Submission.create!(url: "", file: #raw_file, description: "Please edit this description", work_type: "other", date_completed: DateTime.now.to_date)
...
end
private
def parse_raw_upload
if env['HTTP_X_FILE_UPLOAD'] == 'true'
#raw_file = env['rack.input']
#raw_file.class.class_eval { attr_accessor :original_filename, :content_type }
#raw_file.original_filename = env['HTTP_X_FILE_NAME']
#raw_file.content_type = env['HTTP_X_MIME_TYPE']
end
end
Looking at the request itself all the headers are set (X_MIME_TYPE, X_FILE_NAME) etc.
Any ideas?
Thanks in advance!
The example you're cribbing from expects the file stream to be a StringIO object, but Passenger is giving you a PhusionPassenger::Utils::RewindableInput object instead.
Fortunately, a RewindableInput is duckalike to StringIO for this case, so Paperclip's StringioAdapter can be used to wrap your upload stream.
Inside the if block in your parse_raw_upload, at the end, do:
if #raw_file.class.name == 'PhusionPassenger::Utils::RewindableInput'
#raw_file = Paperclip::StringioAdapter.new(#raw_file)
end

encoding error when uploading image via paperclip

I'm trying to upload an image to paperclip and save it to s3. However, I get the following error in my console
!! Unexpected error while processing request: invalid byte sequence in UTF-8
There are a few responses on StackOverflow about how to resolve this problem, though most point to the original solution being an update to Rack. However, I'm using Ruby 1.9.3 and Rails 3.1.3, and believe I don't have Rack (I haven't installed it as a Gem, should I??).
The filenames that I've been trying are fairly simple, so I'm assuming the issue is in the actual file, but I'm not sure how to debug which upload variable the error is coming from. Rails isn't putting any of these errors in the log files, so I can't seem to get more details.
My controller is fairly simple, just like the example on the paperclip github documentation
def create
wine_photo = WinePhoto.create(params[:wine_photo])
return render :json => wine_photo
end
though originally I used the more common
wine_photo - WinePhoto.new(params[:wine_photo])
if wine_photo.save
return render :json => wine_photo
else
return render :json => wine_photo.errors
end
My model (which I doubt is very helpful) is
class WinePhoto true
validates_with AttachmentPresenceValidator, :attributes => :photo
belongs_to :wine
belongs_to :user
def photo_url
photo.url
end
end
based on this response on stackoverflow, Ruby Invalid Byte Sequence in UTF-8, I've tried the below in my controller
def create
wine_photo = WinePhoto.new(params[:wine_photo])
wine_photo.photo = IO.read(wine_photo.photo).force_encoding("ISO-8859-1").encode("utf-8", replace: nil)
...
but still got the error.
Any suggestions on how to get past this encoding issue? Is there a way to confirm that the error is coming from the file being uploaded?
My upload code (ajax) is
save_photo: function(){
var file = document.getElementById('file_api').files[0];
console.log(file);
var xhr = new XMLHttpRequest();
if (xhr.upload && file.type == "image/jpeg" ) {
// create progress bar
var o = document.getElementById("progress");
var progress = o.appendChild(document.createElement("p"));
progress.appendChild(document.createTextNode("upload " + file.name));
// progress bar
xhr.upload.addEventListener("progress", function(e) {
var pc = parseInt(100 - (e.loaded / e.total * 100));
progress.style.backgroundPosition = pc + "% 0";
}, false);
// file received/failed
xhr.onreadystatechange = function(e) {
if (xhr.readyState == 4) {
progress.className = (xhr.status == 200 ? "success" : "failure");
}
};
// start upload
xhr.open("POST", document.getElementById("add_photo").action, true);
xhr.setRequestHeader("X_FILENAME", file.name);
xhr.send(file);
}
}
and the params for file are
File {webkitRelativePath: "", lastModifiedDate: Thu Nov 10 2011 09:40:39 GMT+1100 (AUS Eastern Summer Time), name: "WP_000012.jpg", type: "image/jpeg", size: 1344450}
After two days of messing with this, it turns out the problem was in my ajax upload, rails wasn't getting the file field at all.
I followed this blog post to get the ajax upload working,
https://github.com/newbamboo/example-ajax-upload/blob/master/public/index.html
and changed the name in my input file to < input type="file" name="wine_photo[photo]" > where before the name was just photo.
the html form now also has
<input name="utf8" type="hidden" value="✓">

encoding error with ajax upload (qqfile) and paperclip

I'm trying to get an ajax upload working with rails 3.1.3 and paperclip.
I found this solution to my problem Rails 3 get raw post data and write it to tmp file, but using this, I get an 'encoding undefined conversion error "\xFF" from ASCII-8BIT to UTF-8.
The error occurs at the line #user.photo = #user.photo = QqFile.parse(params[:qqfile], request)
I have not edited the code supplied in the previous answer, but I'll include it here so you don't have to switch back and forth.
the gem list paperclip, returns 2.5.2, 2.4.5, 2.3.8
my controller
def create
#user = User.new(params[:user])
#user.photo = QqFile.parse(params[:qqfile], request)
if #user.save
return render :json => #user
else
return render :json => #user.errors
end
end
qq_file.rb
# encoding: utf-8
require 'digest/sha1'
require 'mime/types'
# Usage (paperclip example)
# #asset.data = QqFile.new(params[:qqfile], request)
class QqFile < ::Tempfile
def initialize(filename, request, tmpdir = Dir::tmpdir)
#original_filename = filename
#request = request
super Digest::SHA1.hexdigest(filename), tmpdir
fetch
end
def self.parse(*args)
return args.first unless args.first.is_a?(String)
new(*args)
end
def fetch
self.write #request.raw_post
self.rewind
self
end
def original_filename
#original_filename
end
def content_type
types = MIME::Types.type_for(#request.content_type)
types.empty? ? #request.content_type : types.first.to_s
end
end
This was an encoding error related to Ruby 1.9.2 (or I believe Ruby 1.9+).
this github post lead to the answer
https://github.com/lassebunk/webcam_app/issues/1
You must specify raw_post.force_encoding("UTF-8") when reading an upload as far as I could tell (I'm not a great programmer).

Paperclip- validate pdfs with content_type='application/octet-stream'

I was using paperclip for file upload. with validations as below:
validates_attachment_content_type :upload, :content_type=>['application/pdf'],
:if => Proc.new { |module_file| !module_file.upload_file_name.blank? },
:message => "must be in '.pdf' format"
But, my client complained today that he is not able to upload pdf. After investigating I come to know from request headers is that the file being submitted had content_type=application/octet-stream.
Allowing application/octet-stream will allow many type of files for upload.
Please suggest a solution to deal with this.
Seems like paperclip doesn't detect content type correctly. Here is how I was able to fix it using custom content-type detection and validation (code in model):
VALID_CONTENT_TYPES = ["application/zip", "application/x-zip", "application/x-zip-compressed", "application/pdf", "application/x-pdf"]
before_validation(:on => :create) do |file|
if file.media_content_type == 'application/octet-stream'
mime_type = MIME::Types.type_for(file.media_file_name)
file.media_content_type = mime_type.first.content_type if mime_type.first
end
end
validate :attachment_content_type
def attachment_content_type
errors.add(:media, "type is not allowed") unless VALID_CONTENT_TYPES.include?(self.media_content_type)
end
Based on the above, here's what I ended up with which is compatible with PaperClip 4.2 and Rails 4:
before_post_process on: :create do
if media_content_type == 'application/octet-stream'
mime_type = MIME::Types.type_for(media_file_name)
self.media_content_type = mime_type.first.to_s if mime_type.first
end
end
For paperclip 3.3 and Rails 3, I did this a bit differently
before_validation on: :create do
if media_content_type == 'application/octet-stream'
mime_type = MIME::Types.type_for(media_file_name)
self.media_content_type = mime_type.first if mime_type.first
end
end
validates_attachment :media, content_type: { content_type: VALID_CONTENT_TYPES }
By the way, i needed to do this because testing with Capybara and phantom js using attach_file did not generate the correct mime type for some files.