¿Cómo cargar archivos Blob y Base64 con Active Storage y Ajax?

Por William Romero

Creado el 05/06/2019

Cuando necesitamos cargar archivos usando Ruby on Rails, podemos encontrar un gran panorama de gemas que pueden ser útiles para desarrollar dicha tarea. Por ello, nos es necesario decidir cual de todas ellas utilizaremos para nuestro proyecto. En mi caso personal, me encuentro desarrollando una plataforma con la última versión de Rails (5.2), por lo que me he enfrentado con algunos inconvenientes de escasa documentación y entre ellos, el de cargar de forma asíncrona, imágenes o archivos utilizando Active Storage. A pesar, de que en su sitio web, parecería bien documentado todo lo relativo a este apartado, no existe información sobre como cargar archivos o imágenes que se envíen a nuestro servidor de formato binario o codificada en base64. Por ello, a continuación les explicaré mi experiencia, esperando que les sea útil a todos.

Cargar archivo BASE64 

En este caso, cargaremos un archivo codificado en Base64 desde Javascript haciendo uso de FileReader( ) y .readAsDataURL( ), los cuales nos convertirán en un archivo en Base64. A continuación, el código de Javascript y Ajax.

var ffachada = document.querySelector('.ffachada'); // InputFile
var idData = document.querySelector('idData).innerHTML; // Crgando ID record del formulario
var formElm = document.querySelector('.edit_visitors').getAttribute('action');
var imgBSC;

ffachada.addEventListener('change', (e) => {
e.preventDefault();
var file = e.target.files[0]; // Tomamos la imagen del InputFile
var reader = new FileReader(); // Creamos un objeto FileReader
reader.readAsDataURL(file); // Codificador a Base64
reader.onload = () => {
imgBSC = reader.result;
$.ajax({
url: `/dashboard/visitors/${idData}/images`,
type: 'post',
data: {foto_fachada: imgBSC},
success: function(response) {
console.log(response)
}
});
}
});

Ya habíendo enviado el archivo a nuestro controlador, realizaremos lo siguiente para almacenar decodificar y almacenar nuestro archivo con los estándares de Active Storage.

require 'base64'
require 'stringio'

class VisitorsController < ApplicationController
def saveimages
@visita = Visita.find(params[:id])
filename = "visita-#{@visita}-#{Time.current.to_i.to_s}"
base64_image = params[:foto_fachada].sub(/^data:.*,/, '')
decoded_image = Base64.decode64(base64_image)
image_io = StringIO.new(decoded_image)
@resvar = { io: image_io, filename: filename }
@avaluo.geolocation.foto_fachada.attach(@resvar)
end
end

Y ahora, si nos dirijimos a nuestra base de datos, podremos visualizar que el registro, ha sido creado.

 

Cargar archivo BLOB

En este caso, cargaremos un archivo desde Javascript (AJAX) haciendo uso del Objeto FormData, el cual genera una representación binaria del archivo en la cual incluye al mismo, identificándolo con una estructura de llaves y valores.

var ffachada = document.querySelector('.ffachada'); // InputFile
var idData = document.querySelector('idData').innerHTML; // Crgando ID record del formulario
var imgBSC;

ffachada.addEventListener('change', (e) => {
e.preventDefault();
var file = e.target.files[0]; // Tomamos la imagen del InputFile
var formData = new FormData();
// Creamos un objeto FormData, que contendrá nuestro archivo
formData.append('foto_fachada', file);
// Generamos una llave la cual contendrá el valor (archivo Blob)
$.ajax({
url: `/dashboard/visitors/${idData}/saveimages`,
type: 'post',
processData: false,
contentType: false,
data: formData // Lo incluímos para enviarlo al controlador.
});
}
});

Luego de ello, en el controlador, pasaremos el parámetro foto_fachada, la cual se introducirá como un objeto IO en el cual los campos como nombre de archivo, el tipo de contenido y el propio archivo, serán tomados de la información del mismo y asignados al método Attach de Active Storage.

require 'base64'
require 'stringio'

class VisitorsController < ApplicationController
def saveimages
puts params[:foto_fachada]
@visita = Visita.find(params[:id])
# Tomar el record al que pertenece el parámetro
@visita.geolocation.foto_fachada.attach(
io: params[:foto_fachada], # Colocamos el archivo
filename: params[:foto_fachada].original_filename, #Colocamos el namefile
content_type: params[:foto_fachada].content_type #Colocamos typefile
)
end
end

Espero que te haya sido de mucha ayuda.