Subir videos con Ruby on Rails
Uno de los grandes beneficios de trabajar con una plataforma de desarrollo como es Ruby on Rails es que nos permite ahorrarnos líneas de código que en otras plataformas o frameworks nos llevaría tiempo y esfuerzo hacer que funcionara correctamente.
La importancia de la velocidad en el desarrollo de nuestras aplicaciones es cada vez más importante y Rails nos ofrece un desarrollo con menos esfuerzo y mucho mayor rapidez.
A continuación mostraré de qué forma se puede subir un video con formato FLV al servidor.
El primer paso, asumiendo que ya se encuentra instalado Rails en nuestro sistema, será crear un nuevo proyecto, para ello bastará con utilizar el comando rails seguido del nombre que queremos darle a nuestro proyecto.
rails subirVideo
Lo cual nos creará un nuevo directorio subirVideo en nuestro directorio actual, por lo que es importante estar en el directorio donde queremos crear nuestro proyecto.
Dentro de nuestro proyecto crearemos nuestro controlador videos que será el encargado de gestionar la subida del vídeo,para tal propósito se utiliza el comando generate que se encuentra dentro del directorio script de nuestro proyecto, la forma para crear el controlador es:
script/generate controller videosAl ejecutar este comando se creará una serie de archivos y directorios:
exists app/controllers/ exists app/helpers/ create app/views/videos exists test/functional/ exists test/unit/helpers/ create app/controllers/videos_controller.rb create test/functional/videos_controller_test.rb create app/helpers/videos_helper.rb create test/unit/helpers/videos_helper_test.rb
A partir de este momento podemos empezar a desarrollar nuestra aplicación, abrimos el archivo videos_controller.rb y crearemos una nueva acción llamada index la cual será la endargada de mostrar el formulario que permitirá al usuario escoger el archivo que quiere subir. Nuestro archivo queda de la siguiente manera:
class VideosController < ApplicationController def index end end
Lo siguiente que haremos será crear una vista en el directorio app/views/videos on el nombre index.html.erb para esa acción que creamos, en ésta se encontrará todo el código HTML que se mostrará en el navegador, lo que haremos será crear un archivo con el siguiente contenido:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Subir Video</title> </head> <body> <div> <% form_tag 'videos/upload', :id => 'subir', :multipart => true do %> <h4>Escoja un video</h4> <p>El video debe tener la extensión flv</p> <%= file_field_tag "video" %><br /> <%= submit_tag "Subir video" %> <% end %> </div> </body> </html>
Que nos mostrará una pantalla como esta:

la línea:
<% form_tag 'videos/upload', :id => 'subir', :multipart => true do %>
nos ayuda a crear un formulario, la función form_tag es de los llamados helpers que nos ayudan a reducir la cantidad de lineas de código haciendo que nuestras vistas sean prácticamente sólo HTML, ‘videos/upload’ es la dirección en donde se realizará la acción con los datos enviados por el formulario, :multipart => true indica que será un formulario que permitirá enviar archivos al servidor, :id => ’subir’ es el id que se le da al formulario cualquier otro atributo se podría asignar usando la notación :atributo => ‘valor’
<%= file_field_tag "video" %> y <%= submit_tag "Subir video" %>
son al igual que form_tag helpers para definir inputs del tipo file y del tipo submit respectivamente, para file_field_tag, “video” es el name y el id que tendrá el campo y para submit_tag, “Subir video” será el valor que se mostrará en el botón.
Ya teniendo nuestra vista es necesario crear otra acción llamada upload que será donde se realicen las operaciones con el video una vez esté en el servidor.
def upload if request.post? #asigna la información del video en archivo archivo = params[:video] #nombre original del archivo name = archivo.original_filename #ruta donde se guardará el video directory = "public/flv" # crear la ruta del archivo path = File.join(directory, name) extensionArchivo = name.slice(name.rindex("."), name.length).downcase #verifica que la extensión sea la correcta if extensionArchivo == '.flv' # crear el archivo File.open(path, "wb") { |f| f.write(archivo.read) } #guarda la información que se mostrará @archivoGuardado = true @nombreArchivo = name else #en caso de que no sea correcta la extensión muestra un mensaje de error render :text => '<p>El archivo debe tener la extensión flv</p> de click <a href="../videos"> aquí</a> para volver a intentarlo' end end end
Lo primero que hacemos es verificar que se haya enviado el formulario mediante post utilizando:
request.post?Sí el archivo se envio lo primero que hacemos es asignar el video que subimos a una variable en estea caso archivo params nos permite acceder a los datos enviados mediante POST y para acceder a cada campo enviado utilizamos params[:nombreDelCampo] en este caso params[:video], utilizaremos en nombre que tenía el archivo al ser subido por el usuario así que almacenamos el nombre original en la variable name y en directory almacenamos la ruta donde se guardará el archivo en el servidor (“public/flv”), en path tendremos la ruta completa del archivo por ejemplo: public/flv/miVideo.flv, hasta ahora no hemos almacenado el archivo en el servidor, primero debemos saber si la extensión es la correcta para eso la obtenemos mediante:
extensionArchivo = name.slice(name.rindex("."), name.length).downcase
que lo que hace es extraer la cadena que se forma a partir del útimo punto a la derecha del nombre del archivo hasta el final del nombre del archivo y lo convierte en minúsculas, así no importa que la extensión sea .flv o .FLV.
Si la extensión es la correcta entonces pasamos el archivo al directorio public/flv mediante:
File.open(path, "wb") { |f| f.write(archivo.read) }
que crea un archivo en la ruta path (incluyendo el nombre) a partir del contenido del archivo que subimos almacenado en archivo, wb nos indica que el archivo se abre para escritura en modo binario.
Después de crear el archivo guardamos los datos en variables que podremos utilizar en la vista upload, que es el nombre y una variable que nos indica si el archivo se guardó.
La vista que nos mostrará que el archivo se guardó correctamente como se mencionó antes tendrá el nombre upload y tendra el siguiente contenido:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Archivo procesado</title> </head> <body> <% if @archivoGuardado %> <p>El archivo <%= @nombreArchivo %> se subio correctamente</p> <%end%> </body> </html>
Que comprueba que el archivo se haya guardado corectamente para mostrar un mensaje como este:
El archivo miVideo.flv se subio corectamente
En caso de que la extensión del archivo no fuera ni .flv ni .FLV entonces inmediatamente nos mostrará un mensaje de error como este:
Para hacer esto hacemos uso de render :text para mostrar el mensaje.
Hasta ahora la aplicación funciona correctamente pero sería mejor que la subida del archivo se realizara en segundo plano para que el usuario no crea que la página está congelada, para hacer esto haremos uso de Javascript y un iframe oculto.
Agregaremos un iframe a la vista index y un área para los posibles mensajes de error, entonces nuestra vista quedará de la siguiente forma:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <%= stylesheet_link_tag 'estilos' %> <%= javascript_include_tag :defaults %> <%= javascript_include_tag "validar" %> <title>Subir Video</title> </head> <body> <div> <% form_tag 'videos/upload', :id => 'subir', :multipart => true do %> <h4>Escoja un video</h4> <p>El video debe tener la extensión flv</p> <%= file_field_tag "video" %><br /> <%= submit_tag "Subir video" %> <% end %> </div> <div id="mensajes"> </div> <div id="contenedorIframe"> <iframe name="Upload" id="Upload"></iframe> </div> </body> </html>
Debemos ocultar el iframe a la vista del usuario para ello creamos una hoja de estilos en la carpeta public/stylesheets llamada estilos.css con el siguiente contenido:
#Upload{ display:none; }
Se pudo evitar esto haciendo:
<iframe name="Upload" id="Upload" style="display:none"></iframe>
pero es mejor separar el contenido de la presentación.
Para incluir la hoja de estilos usamos el helper stylesheet_link_tag con el nombre de nuestra hoja de estilos, la única condicion es que esté en el directorio stylesheets:
<%= stylesheet_link_tag 'estilos' %>
Cargamos las librerías de javascript necesarias para realizar las nuestras acciones, utilizamos e l helper javascript_include_tag con la misma condicion que las hojas de estilo, debe estar en el directorio javascripts, utilizo :defaults para que todas las librerias incluidas por defecto en Rails se carguen pero basta con ‘prototype’ ya que es la única que se utiliza, crearemos un archivo llamado validar.js en public/javascripts y lo incluimos:
<%= javascript_include_tag "validar" %>
en este archivo pondremos lo siguiente:
window.onload = function() { var formulario = $('subir'); formulario.target = "Upload"; formulario.onsubmit = function(){ var listoEnvio = true; var archivo = $('video').value; var extension = (archivo.substring(archivo.lastIndexOf("."))).toLowerCase(); if(extension == '') { $('mensajes').update("Seleccione un archivo"); listoEnvio = false; } else { //Si existe archivo se comprueba que sea .flv if(extension != '.flv') { //En caso de que no sea esa la extensión se muestra un mensaje y // listoEnvio se vuelve false $('mensajes').update("Seleccione un archivo del tipo correcto"); listoEnvio = false; } else { //En caso de que sea la extensión correcta se muestra un gif //mientras se sube el archivo $('mensajes').update('<img src="/images/cargando.gif" />'); } } //En caso de error no se envía el archivo al servidor return listoEnvio; } }
Asignamos nuestro formulario subir a la variable formulario y cambiamos el target hacia el iframe que creamos antes
formulario.target = "Upload";
Lo cambiamos mediante javascript sobre todo por accesisbilidad, para que aquellos que tengan javascript desactivado puedan utilizar normalmente el formulario, ahora debemos hacer la validación de la extensión al momento de que se envie el formulario y al igual que hicimos con Rails comprobamos la extensión y mostramos los mensajes en el área que destinamos a los posibles mensajes que quisieramos mostrar

En caso de error asignamos false a listoEnvio para evitar que se envíe el formulario, si todo marcha bien entonces se enviará al servidor y mostrará una imagen aanimada mientras se sube el archivo.

El siguiente paso es hacer que la vista upload responda a la página principal mediante javascript, debemos agregar algunas lineas de código para adaptarlo:
<% if @archivoGuardado %> <noscript> <p>El archivo <%= @nombreArchivo %> se subio correctamente</p> </noscript> <script type="text/javascript"> if(parent.document.getElementById("contenedorIframe")) { parent.$("subir").reset(); parent.$("mensajes").update("El archivo se subio correctamente") } </script> <%end%>
Lo ahora lo que hace es que si Javascript no está activado mostrará el mensaje en pantalla pero si está activado y upload se está ejecutando en el iframe el formulario se reiniciará y se mostrará un mensaje indicando que el archivo se subio correctamente, se utiliza parent porque el iframe “Upload” es hijo de la ventana principal entonces si llegara a ejecutar esta accion por separado comprobaría que esista el elemento contenedorIframe para hace la acción si no no hará nada.

Y listo, tenemos un formulario que sube un video en formato FLV con Javascript no obstrusivo.





Hey, muchas gracias por el articulo viejo. Lo malo del ruby es que no se explican las cosas de manera tan sencilla com olo hiciste aqui, me ahorraste muchas horas de busqueda de como subir un archivo al servidor. Me cayo al dedo tu articulo, gracias.
Muchas gracias, por el comentario.
Estamos procurando mejorar la calidad de lo que publicamos aquí en Ubicuos y te animo Johan a preguntar tus dudas sobre Ruby y Rails aquí.
Un saludo.
Una pregunta que necesito tener en el servidor para poder llamar a estas bibliotecas??? osea esto es ruby? como se si mi servidor corre esos codigos?
por otro lado este tutorial q haces guarda fisicamente los archivos… hay forma de hacerlo guardar en la base de datos?
En el servidor es necesario tener instalado Ruby (http://www.ruby-lang.org) y el framework Rails (http://www.rubyonrails.org), para utilizar el ejemplo, puedes saber si tienes soporte de ruby en tu servidor, revisando en la documentación del hosting (muchos no lo ofrecen, otros sí) o si tienes acceso ssh teclea
y ve si te sale algo como esto:ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux]
No es recomendable guardar los archivos en la base de datos, si quieres evitar que las personas tengan acceso a tus archivos puedes guardarlos en una carpeta no pública en el servidor o utilizar si usas Apache como servidor un archivo .htaccess para restringir el acceso, cuando guardas los archivos en una base de datos tienes que realizar mucho más procesamiento y tu aplicación se irá haciendo cada vez más y más lenta.
Hola muy buen articulo, yo apenas voy empezando en esto y como en la escuela tengo que hacer una aplicacion que maneja BD entonces se me ocurrio hacerlo con RoR, estoy empezando y ya lei algo, lo que quiero hacer es que la aplicacion maneje una BD de peliculas, donde la tabla tiene diferentes campos como titulo, etc. pero hasy dos campos mas que quiero incluir: imagen y trailer.
Asi que lo que quiero es subir tanto imagenes y videos. Mi pregunta es como muestro el video siguiendo tu articulo.
Por tu atencion gracias.
El mostrar el vídeo es algo interesante, por que dependiendo el formato (.flv,.mov,.wmv) depende lo que hay que realizar.
El caso de los vídeos en .flv, es muy sencillo, puedes utilizar el flowplayer para integrarlo en tu aplicación.
Si tienes algún problema, no tengas duda en preguntar.
La página de flowplayer es:
http://flowplayer.org/
Gracias por tu respuesta Daniel, y como puedo integrar flowplayer en mi aplicacion…gracias.
Es bastante sencillo, primero desde tu vista en Rails genera los links a los archivos que subiste con una clase vídeo algo así:
Asigna el estilo en el CSS (ancho, alto,etc) para tu vídeo en la clase vídeo.
Después incluye el archivo de javascript de flowplayer
y finalmente ejecuta flowplayer utilizando el siguiente javascript
<script type="text/javascript"> flowplayer("a.video", "/swf/flowplayer-3.1.5.swf"); </script>Espero te sirva, si tienes preguntas no dudes en escribirlas.
Daniel muchisisimas gracias, tu explicacion me fue de gran ayuda y por fin hoy he terminado la aplicacion.
Gracias.
De nada con mucho gusto, si tienes otras dudas de Rails no dudes en escribirlas y buscaremos darle solución.