How to save base64 encoded image with ruby on rails and carrierwave - ruby-on-rails

I receive a base64 encoded image from another server and need to save it to my postgres database. I am using rails 6 and carrierwave. Here is my model:
class Quin < ApplicationRecord
before_create :create_graphic
mount_base64_uploader :new_image, NewImageUploader
def create_graphic
url = "https://my-api-url.com"
url_response = HTTParty.post(url,:body => data)
self.new_image = "data:image/png;base64," + url_response.parsed_response
puts "parsed response is #{url_response.parsed_response.inspect}"
end
end
For some reason, when I save, new_image is just saved as nil. I know I am receiving a response. It's really long but here's a truncated sample from logs:
parsed response is "\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x05\xA0\x00\x00\x05\xA0\b\x02\x00\x00\x00'\xC2s\x9F\x00\x01\x00\x00IDATx\x9C\xEC\xFD[\x93$\xD9u\xE7\x8B\xFD\xD7\xF2\xAC\xCA\xEA\xAA\x06\x01j\xCE\x90U\r\x1C\xE9\x98I/2=\xC8Ht\x17\xCD\xF4A\bp83\x94t\x8E$3}#\x9D3:g\x86\x04\x89\xA6\x1D\x99\x1E\xF4\r\xC0\xE1H\x86jp(\xD3\x9B\xDEd\x04\xD0] n\x8D\xEE\xCA\xAC\x88\xCC\xF0\xB5\xF4\xB0\xF6\xCD/q\xCB\xCC\xC8\xC8\xA8\xFA\xFF:;+#\xC2}\xFB\xF6\xED\xDB=\xF6\xFE\xEFu\x11w\a!\x84\x10B\b!\x84\x10B\xC8)\xA3\xC7\xAE\x00!\x84\x10B\b!\x84\x10B\xC8m\xA1\xC0A\b!\x84\x10B\b!\x84\x90\x93\x87\x02\a!\x84\x10B\b!\x84\x10BN\x1E\n\x1C\x84\x10B\b!\x84\x10B\b9y(p\x10B\b!\x84\x10B\b!\xE4\xE4\xA1\xC0A\b!\x84\x10B\b!\x84\x90\x93\x87\x02\a!\x84\x10B\b!\x84\x10BN\x1E\n\x1C\x84\x10B\b!
How do I fix this and save the base64 encoded image that is returned?

Related

Rails Httparty JSON to params to save

Rails 4.5 Ruby 2.3.1
I am getting json from an API and trying to store the following into a model CLrates
1. timestamp as unix time (date)
2. Currency_code (string)
3. quote (decimal monetary value)
I can use the following in irb after parsing the json and know how to get the elements individually using: response["quotes"]. How can I generate params to be saved in the model above when the body is as follows:
irb(main):036:0> puts response.body
{
"success":true,
"terms":"https:\/\/xxxxx.com\/terms",
"privacy":"https:\/\/xxxxx.com\/privacy",
"timestamp":1504817289,
"source":"USD",
"quotes":{
"USDAED":3.672703,
"USDAFN":68.360001,
"USDCUC":1,
"USDCUP":26.5,
"USDCVE":91.699997,
"USDCZK":21.718701,
............ many more lines removed for brevity
"USDZWL":322.355011
}
I can do this using a separate associated model but have very little idea how to create the params to save to a single table.
The following links got me to this point and well worth a read if you need info on httparty GET (client):
1. http://www.rubydoc.info/github/jnunemaker/httparty/HTTParty/
2. http://eric-price.net/blog/rails-api-wrapper/
3. https://www.driftingruby.com/episodes/playing-with-json
The class and method in lib/clayer.rb:
class clayer
include HTTParty
format :json
read_timeout 10
def self.get_quotes
response = HTTParty.get('http://www.nnnnnnn.net/api/live?
access_key=nnnnnnnnnn&format=1')
end
end
I used irb as I am still learning how to run this through rails c. This will be called in the controller and saved however need to work out how to get the params from the json
Thanks for the help
OK: after digging I think I am on the right track
I get the response["QUOTES"], loop through them and build the params required saving each at the end of the loop
rates = response["QUOTES"]
rates.each do |k,v|
clrate = Realtimerates.new
clrate.date = response["timestamp"]
clrate.countrycode = "#{k}"
clrate.price = "#{v}"
clrate.save
end
Going to give this a whirl
In model
class Realtimerate < ActiveRecord::Base
include HTTParty
format :json
read_timeout 5
def self.get_cl_rates
response = HTTParty.get('http://www.mmmmm.net/api/live?access_key="key"&format=1')
rates = response["quotes"]
rates.each do |k,v|
create!(
date: Time.at(response["timestamp"]),
country_code: "#{k}",
price: "#{v}")
end
end
end
In the controller:
def index
Realtimerate.get_cl_rates
#realtimerates = Realtimerate.all
end
This is working and shows latest GET.
You already have a hash in your response.body. All you need to do now is to assign the relevant key-value to your model's attributes. e.g.
clrate = ClRate.new
res = response.body
clate.time = res["timestamp"]
...
clate.save

Post image from Rails

I've got a Base64 encoded image coming in to my application. I want to re-post that image somewhere else, but it's setting the content-type to multipart/form-data at the destination. How do I upload this image?
file_name = permitted_params[:file_name]
file_contents = permitted_params[:file_contents]
file = Tempfile.new( file_name )
file.binmode
file.write( Base64.decode64( file_contents ) )
file.rewind()
raw_response = RestClient.put(
url,
{ 'upload' => file, :content_type => 'image/jpeg' },
:headers => {:content_type => 'image/jpeg'}
)
UPDATE (SOLVED)
I needed to use RestClient because I needed to pass it through to another server (hence the 'url' in the PUT).
My problem was in decoding the image I wasn't stripping out the
data:image/jpeg;base64,
then with this code:
raw_response = RestClient.put(url,
file_binary,
{:content_type => imageContentType})
I was able to get it to put the image and set the correct content-type. The answer below did help though, because I tried it to make sure the image was being decoded properly and it wasn't.
It is quite simple to do. First, you need to decode base64 encoded file. You will get binary file representation. Next use send_data from ActionController to send binary data. Also I have set a filename so it will be delivered to the user.
require 'base64'
class SomeController < ApplicationController
def some_action
file_name = permitted_params[:file_name]
file_base64_contents = permitted_params[:file_contents]
file_binary_contents = Base64.decode64(file_base64_contents)
# https://apidock.com/rails/ActionController/Streaming/send_data
send_data file_binary_contents, filename: file_name
end
end
I'll suggest you to update this implementation with error handling to improve security of your app. One more thing, don't use RestClient. Why do you need it here? Rails gives you all needed things for HTTP communication from controller.
If you have any questions about this please ask. Good luck.

Save base64 images with paperclip

I'm currently working on application for saving base64-encoded image as normal png image. I have following code in my controller's create action:
if #campaign.save
unless params[:campaign][:design_attributes][:front_svg].empty?
data = params[:campaign][:design_attributes][:front_svg]
File.open(params[:campaign][:design_attributes][:img_front_file_name], 'wb') do |f|
f.write(ActiveSupport::Base64.decode64(data))
end
f = File.open(params[:campaign][:design_attributes][:img_front_file_name])
#campaign.design.img_front = f
end
end
front_svg params contains base64 data. When I try to call action, I get following error:
no implicit conversion of nil into String
How do I save base64 encoded image using paperclip?
Change f.write like this,
decoded_data = ActiveSupport::Base64.decode64(data)
f.write(StringIO.new(decoded_data))

How can I programmatically generate a PDF and save it on S3 using Carrierwave?

I am trying to generate a PDF using PDFKit
html = '<b>test</b>'
kit = PDFKit.new(html, :page_size => 'Letter')
pdf = kit.to_pdf
this works fine, and I can save the data to disk if I want to.
I have a simple model :
class Attachment < ActiveRecord::Base
mount_uploader :file, FileUploader, mount_on: :filename
end
when I do :
a = Attachment.new
a.file = pdf
I receive the following error :
ArgumentError: string contains null byte
I prefer not to have to save the PDF to disk before uploading because I'll be using Heroku.
As the gist by William is not working for me, here is what I did to resolve the problem:
html = '<html><head></head><body>foo!</body></html>'
file = PDFKit.new html
file.to_pdf.gsub(/\0/, '')
The idea comes from the answer to this question. Side effects may apply.

Rails + CouchDb binary file upload to Database

Simple-Stored is based on top of CouchPotato for handling CouchDb in rails. While trying to upload files to the couchdb we have tryied using base64, json post and nothing seems to work quite right; we are trying to upload to the _attachments propertie of a document already stored.
Having the model like this :
class Patient
include SimplyStored::Couch
end
and in the controller while receiving the file trough the update action
def update
#patient = Patient.find(params[:id])
if params[:patient][:_attachments]
attachement = params[:patient][:_attachments]
filedata = attachement.tempfile.read
data = Base64.encode64(filedata).gsub(/\n/, '')
type = attachement.content_type
or_name = attachement.original_filename
#patient._attachments = {or_name => {'data' => data, 'content_type' => type}}
#patient.save
return render :json => #patient._attachments
end
end
Now the fun part is that I can see that #patient._acttachments has the file itself and that is what is returning in the render after the .save; but it is not actually saving it on the couchdb database.
Any ideas why is not doing the save or should I try to just push the _attachment to the couchdb database. ? (which by the way always returns a 500 error :( )
the solution it's very simple, based on the couchpotato website, you actually don't need to convert it to base64 here is the example of code working
if params[:patient][:_attachments]
attachement = params[:patient][:_attachments]
data = attachement.tempfile.read
type = attachement.content_type
or_name = attachement.original_filename
params[:patient][:_attachments] = {or_name => {'data' => data, 'content_type' => type}}
end
if #patient.update_attributes(params[:patient]) #blah blah blah
since the values are in the [:patient][:_attachments] params, you just need to pass it as another param tested and working.
Also you need to define your patients model as
property :_attachments
dunno if that is required but I did it.
I know I should not ask for money but since I WORK FOUR YOU its only 100 pesos/hour.. see you at the office
cheers
lols
I donno about the Ruby and couchpotato, but I don't think you need to Base64 your attachment. Just read the binary info and write it to request.
my 2cents. :)

Resources