Saltar al contenido

Rieles: Cómo crear un plugin de renderización de PDF personalizado

Antes de sumergirnos en nuestra serie sobre la construcción de grandes aplicaciones web con Rails, echa un vistazo a nuestro tutorial sobre cómo empezar con el popular marco de trabajo.

Comencemos con un rápido repaso de Rails. Rails es un marco de trabajo web dentro del lenguaje de programación Ruby, y también es una gema de Ruby. Las gemas Ruby están compuestas por código, documentación y una gema espectral. El gemspec contiene información sobre la gema, incluyendo lo que hace y quién la creó. Y como la gemspec también es código Ruby, puedes envolver los scripts para generar nombres de archivos. Las gemas facilitan a los programadores Ruby el compartir el código que quieren instalar en sus aplicaciones, y es este proceso el que hace de Ruby on Rails una de las formas más populares de construir grandes aplicaciones web.

Para las aplicaciones web de Ruby, el framework de Rails utiliza la arquitectura MVC para organizar el código. Típicamente, el controlador es responsable de tomar información importante de los modelos y luego enviar esos datos a las vistas para su renderización. Sin embargo, esto no siempre es así, ya que podemos utilizar Rails para generar vistas HTML estáticas, y también podemos hacer que una acción del controlador genere una vista sin el modelo correspondiente.

También puedes usar Bundler para crear tus propias gemas y para manejar la gestión de la dependencia de las gemas.

MVC y el método Rails render()

Rails puede renderizar plantillas y archivos, haciendo posible también renderizar imágenes, texto en bruto y varios formatos de archivo como html, xml, json y txt. Además, podemos añadir más opciones como CSV o PDF al método de renderización integrado en Rails(), que viene empaquetado como parte del framework de Rails. El método render() es la interfaz común para renderizar un determinado modelo o plantilla. En este ejemplo veremos cómo podemos modificar el método render() y devolver un PDF creado con la gema Prawn-esencialmente, creando un plugin Rails que es un renderizador de PDF.

(Nota: Un renderer es un gancho expuesto por el método render() para personalizar su comportamiento. Para más documentación sobre la gema Prawn, consulta el repositorio Github de Prawn).

Como los generadores de Rails incluyen un generador para escribir plugins, crear el plugin que será el renderizador de PDF es fácil. Puedes crear plugins para extender el marco de Rails. Para nuestro ejemplo de renderizador PDF, entra en tu terminal y ejecuta el nuevo plugin de rieles de comandos pdf_renderer.

Después de ejecutar ese comando, localiza tu nuevo plugin Rails generado y ejecuta el comando ls para ver un listado de todos los archivos del directorio del proyecto de tu plugin Rails. Veremos que se ha creado una estructura básica de plugin que contiene un archivo pdf_renderer.gemspec, un Rakefile, un Gemfile y los directorios lib y test. Esto es similar a lo que ocurre si ejecutáramos el comando myapp de Rails para crear una nueva aplicación Rails titulada “myapp”, que genera la estructura esquelética de una nueva aplicación Rails. Una diferencia que notaremos es que al generar el proyecto del plugin, hay un directorio test/dummy que nos permite ejecutar nuestras pruebas dentro de un entorno de aplicación Rails.

El archivo pdf_renderer.gemspec que se generó proporciona la especificación básica de la gema de Rubí. En él se enumeran el autor o autores de la gema, la versión, las dependencias de la gema y los archivos fuente. También permite agrupar el plugin en una gema de Ruby, facilitando así el intercambio de código entre diferentes aplicaciones Rails.

Al igual que en una aplicación Rails normal, el pequeño plugin de ejemplo (para escribir un renderizador) incluye un Gemfile en el que tu gestión de gemas puede ser manejada con Bundler. Esto bloquea nuestro entorno para usar sólo las gemas que aparecen tanto en el archivo pdf_renderer.gemspec como en el Gemfile. No es diferente de usar sólo las gemas listadas en el fichero Gemfile.lock y el Gemfile de una aplicación Rails normal. Las dependencias de las gemas nuevas o actualizadas se agrupan ejecutando los comandos bundle install y bundle update, respectivamente, desde el terminal (mientras esté en la raíz de la aplicación del plugin).

El arranque de la aplicación Rails ficticia creada dentro del directorio de prueba es similar a la forma en que arrancamos cualquier otra aplicación Rails. Pero en este caso, la arrancamos ejecutando el comando rails en nuestra terminal desde el directorio test/dummy de la aplicación del plugin dentro del archivo de proyecto del plugin. El fichero de arranque, que se encuentra en test/dummy/config/boot.rb, es similar al fichero de arranque de cualquier otra aplicación Rails, excepto que éste tiene que apuntar al Gemfile en la raíz del proyecto del plugin, así:

También notarán que el archivo test/dummy/config/application.rb es una versión reducida del archivo /config/application.rb en una aplicación Rails normal:

Ahora, en este ejemplo de hacer un plugin de renderizado de PDF usando Prawn, añadimos la gema Prawn a nuestro Gemfile como lo haríamos en cualquier otra aplicación Rails. Y como la gema Prawn será una dependencia para este ejemplo de plugin Rails, también tenemos que añadirla al archivo pdf_renderer.gemspec añadiendo esta línea de código, s.add_dependency “prawn”, “0.12.0”:

Después de añadir la gema Prawn ejecutaremos el paquete de comandos install, como lo haríamos con cualquier otra aplicación Rails, luego saltaremos a Ruby interactivo ejecutando el comando irb y crearemos un archivo PDF de muestra en irb, así:

En tu editor de texto (en tu directorio de archivos de proyecto que se hizo para escribir este plugin) verás un archivo PDF de muestra. En esta captura de pantalla de mi editor de texto (abajo), verás dos archivos PDF de muestra. Eso es porque cuando creé el primero, el archivo sample.pdf se olvidó de hacer el screencap de la sesión irb. Por lo tanto, hice un segundo archivo PDF de muestra con fines ilustrativos, esto te muestra cómo debe verse la salida de la terminal para la sesión irb.

Volviendo a Prawn, si lees la documentación, verás que Prawn tiene su propia sintaxis para crear archivos PDF. Nos proporciona una API fácil de usar. Sin embargo, no puede convertir archivos HTML en archivos PDF. Si quieres tener la posibilidad de hacerlo, y no encuentras una gema de Ruby que pueda encargarse de esa tarea, puedes considerar la posibilidad de construir tu propia gema de Ruby usando Bundler. Aún así, siempre puedes revisar las gemas disponibles yendo a Rubygems.org y buscando una que ya tenga lo que necesitas. Hay toneladas de nuevas gemas de Ruby que se construyen y suben a Rubygems.org diariamente, así que hay una alta probabilidad de encontrar una que satisfaga las necesidades de tu aplicación.

Compruebe la salida del terminal de los resultados de la prueba para comprobar el código del plugin (imagen abajo). Como en cualquier otro proyecto de Rails, querrás escribir al menos dos pruebas de cordura. Las pruebas y el código de este plugin de renderizado de PDF son bastante sencillos. Cread un archivo de pruebas para vuestras pruebas de integración, /test/integration/pdf_delivery_test.rb, y escribid un par de pruebas de integración sencillas como esta:

Ahora escribimos la primera prueba para verificar que se devuelve un archivo PDF al arrancar la aplicación. Lo hacemos yendo a localhost: 3000/home.pdf con la expectativa de que falle hasta que escribamos el código para decirle a Rails cómo manejar la opción pdf en el método render() dentro del archivo /lib/pdf_renderer.rb, así:

También tendrás que hacer un archivo de visualización, index.pdf.erb, que corresponde a la acción de indexación (que deberías haber escrito como parte de tus métodos básicos de CRUD en el controlador de tu aplicación ficticia). Esto es similar a lo que hacemos cuando creamos el archivo index.html.erb en otras aplicaciones Rails. Por supuesto, también querréis añadir las rutas apropiadas:

Ahora, si haces tus pruebas de rastrillo, puedes divertirte viendo como pasan.

Para ver esto en tu navegador, ve al directorio de prueba y arranca el servidor de rieles. Luego, vaya a localhost: 3000/home.pdf. Deberías ver un formulario PDF emergente que puedes editar. Aquí hay una captura de pantalla mía:

Probablemente se preguntan cómo Rails sabía qué tipo de contenido establecer en la devolución o respuesta a nuestra solicitud. La respuesta es simple. Rails viene con un conjunto pre-empaquetado de formatos registrados y tipos MIME. Podéis comprobarlo examinando el corazón del marco de Rails en rails/actionpack/lib/action_dispatch/http/mime_types.rb. Aquí es donde encontraremos un listado de todos los tipos de contenido pre-empaquetados en Rails, que pueden manejarlo por nosotros: png, jpg, gif, css, html, text, js, bmp, tiff, ics, csv, mpeg, xml, yaml, atom, json, zip y pdf. Podéis verificarlo consultando el repositorio Github de Rails.

Tómese un momento para repasar el código de ese repositorio, y verá que el formato PDF está definido con su tipo de contenido específico. Cuando el usuario (en este caso, nosotros) hizo una petición en el navegador para ver la URL de /home.pdf en localhost, Rails recuperó el formato PDf de la URL y luego lo verificó con el bloque de código format.pdf que se definió con el método de índice (o acción) en el HomeController. Luego procedió a configurar el tipo de contenido correcto antes de invocar el bloque que llamó al método render().

La pila de rieles

La palabra clave aquí para entender la pila de renderizado de Rails es la palabra renderizado en sí misma. Siempre que veas la palabra renderizar, deberías asociarla con todo lo que un usuario ve cuando hace una petición al navegador; todo, desde formularios interactivos hasta respuestas automáticas y vistas.

Rails también se basa en su pila de renderizado para su capacidad de extender el ActionController y el ActionMailer dentro del marco de Rails, (más sobre eso más adelante en esta serie). Tanto el ActionController como el ActionMailer comparten varias características comunes y, de acuerdo con el principio DRY, el código subyacente que rige esas características compartidas fue abstraído a la clase AbstractController; una conveniente superclase pública que utilizan y de la que heredan el ActionController y el ActionMailer.

El AbstractController te permite elegir las funcionalidades que prefieras. Uno de sus módulos incluidos es ActionView. Una de las instancias de ActionView::Base es view_context. Es una instancia de una clase View y, según la documentación de la API, esa clase View debe tener los siguientes métodos: View.new[lookup_context, asigna, controlador]. Es el contexto en el que se evalúan las plantillas de tu proyecto. Cuando se instancian, recibe el método view_assigns() como uno de sus parámetros, que debe devolver un hash. Para descomponerlo un poco mejor, piénsalo de esta manera: La razón por la que el método link_to funciona en una plantilla es porque es un método que está disponible dentro de ActionView::Base.

En cuanto a las asignaciones, hace referencia a todas las variables de instancia del controlador que serán accesibles en la vista. Por eso, siempre que declare una variable de instancia en un controlador, como @productos = Producto.all (donde @producto se designa como una asignación), también estará disponible en las vistas. Ahora, si no quieres que un controlador envíe ninguna asignación a la vista, simplemente anula el método view_assigns() para devolver un hash vacío. Al devolver un hash vacío, no tendrás ninguno de los métodos de controlador (también conocidos como acciones) pasando a la vista.

La configuración de la pila de renderizado de Rails te permite engancharte al proceso de renderizado y personalizarlo con tus propias características. Esta es una cantidad impresionante de poder para tener a tu disposición. Utiliza ese poder con sabiduría y ten siempre presente que no te estás exponiendo o, peor aún, que no estás exponiendo a tus clientes o a tu empleador a posibles agujeros de seguridad. La primera pregunta que deberías hacerte al diseñar tu aplicación es: ¿Cuánto necesito realmente para extender la pila de renderizado?

Para llevar

Ahora que has terminado la primera parte de nuestra serie de marcos de trabajo Rails, deberías saber cómo crear tu propio plugin de renderización de PDF personalizado. Tómate un tiempo para familiarizarte con el proceso y estate atento al próximo tutorial de Rails.

Consigue nuestro contenido primero. En tu bandeja de entrada.

1229

Contribuyente

Jacqueline Homan

es un consultor, autor de Pluralsight e ingeniero de software para AstralAR, LLC que se especializa en investigación combinatoria y de operaciones. Sus herramientas preferidas son F# y Ruby. Jacqueline ha estado en el campo de la informática desde 2013, trabajando principalmente en proyectos centrados en la optimización y el análisis de datos. Sus compañeros de equipo en AstralAR la apodaron “Capitán Cálculo”. Puedes seguirla en Twitter en: @jacquelinehoman.