miércoles, 13 de marzo de 2013

Subir Ficheros en Rails con Mongodb y GridFS

Cuando subimos ficheros (imágenes, vídeos, ...) con una aplicación web, hay ocasiones en las que no se pueden guardar en el FileSystem del propio servidor. Ya sea por espacios, permisos de escritura, tener varias instancias levantadas, ...
Para solucionarlo hay varias opciones:

Una es almacenarlo en una BBDD SQL como un dato BLOB (Binary Large Objects). Por regla general, la pega es que  necesitaremos una conversión previa de bytes, que es lo que guarda la base de datos, al fichero en sí.

Otra opción es usar un almacenamiento en la nube, por medio de Amazon S3, por ejemplo. De esta manera subimos el fichero directamente al servidor que nos de el servicio, y cuando se necesite acceder, lo haremos por URL. El único problema es que estos servicios suelen tener un coste añadido, aunque no demasiado elevado.

La tercera opción que propongo y que explicaré a continuación, es realizar el almacenamiento en MongoDB.
El límite de datos para un documento de MongoDB tipo BSON es de 16MB, un tamaño que se nos quedará corto para el uso que queremos darle. Para solucionar esto, esta base de datos cuenta con la especificación GridFS, mediante la cual el fichero se divide en trozos (chunks) de 256KB. Además se guarda información relativa al fichero (metadata).

La implementación en Rails es bastante sencilla. En primer lugar, incluimos la gema carrierwave-mongoid en la aplicación. Suponemos que tenemos ya mongoid instalado.
gem "carrierwave-mongoid"

Preparamos el formulario para subir ficheros:

= form_for :image_form, :url => { :controller => "ficheros", :action => :create }, :html => { :method => :post, :id => 'uploadForm', :multipart => true , :remote => true} do |f|
  %p
    = f.file_field :upload_data

  %p
    = submit_tag 'Subir fichero', :class => 'btn btn-primary'

En nuestro controlados, tendremos que tener un modelo que simplemente guarde el ID del fichero para poder acceder, y mediante esta gema, almacenaremos el fichero:


    @fichero = Fichero.new

    grid_fs = Mongoid::GridFs
    g = grid_fs.put(params[:image_form][:upload_data])

    @fichero.idfichero = g.id.to_s
    @fichero.save

Y con esto ya tenemos el fichero en MongoDB, y referencia a este en idFichero.

Si lo que queremos es mostrar la imagen en alguna página de la aplicación, lo haremos enviando el contenido del fichero desde el controlador. Desde la vista:

= image_tag imageuploaded_path(codigo.id)

imageupload es una ruta al action showimage del controlador:

Y desde el controlador hacemos un send_data:

  def showimage
    grid_fs = Mongoid::GridFs
    file = grid_fs.get(Fichero.find(params[:id]).idfichero)

    send_data file.data, :type => file.contentType, :disposition => 'inline'
  end

En nuestra base de datos de MongoDB nos creará las colecciones: fs.chunks y fs.files


miércoles, 6 de marzo de 2013

Convertir vistas de erb a haml

Al crear una aplicación en rails, los ficheros de vistas, por defecto, se crean de tipo erb. Puede que en ese momento, o más adelante, tras tener más vistas, queramos cambiar a HAML, ya que es una opción más limpia para programar.
Para ello primero incluimos la gema haml-rails en el Gemgile:

gem "haml-rails"
Luego, después de hacer bundle install, ejecutamos el siguiente comando por consola:
find . -name '*erb' | xargs ruby -e 'ARGV.each { |i| puts "html2haml -r #{i} #{i.sub(/erb$/,"haml")}"}' | bash

Con esto, se crearán los ficheros correspondientes de tipo HAML.