Arquitectura marco para proyectos Ruby On Rails

Ruby On Rails es un ecosistema muy variado, con un gran número de gemas (plugins) que permiten el desarrollo rápido de aplicaciones web. Además, existen varios servidores de aplicaciones y servidores web que podemos utilizar en nuestros despliegues.

Este post describe una propuesta de arquitectura modelo para el desarrollo de aplicaciones utilizando Ruby On Rails. No obstante, quiero advertir que no soy un desarrollador RoR experto: este esquema se adapta bien a las aplicaciones que he desarrollado/desplegado en mi vida profesional, pero puede no ser el ideal para otros proyectos.

El objetivo principal de esta arquitectura es conseguir una separación clara de elementos, de modo que se pueda disponer de diferentes versiones de Ruby, Rails y gemas en el mismo servidor. De este modo, dos aplicaciones que utilicen diferentes versiones de Ruby pueden estar desplegadas en la misma máquina, lo que no es conveniente en producción pero muy habitual en entornos de desarrollo o pruebas.

Elementos

Los elementos que se desea configurar para cada aplicación son:

  • Ruby
  • Gemas “Rails” y “Bundler”
  • Otras gemas de la aplicación
  • Servidor de aplicaciones
  • Servidor web

En este ejemplo vamos a utilizar Passenger como servidor de aplicaciones y Apache como servidor web. La comunicación entre ambos elementos se realizará utilizando el módulo de Apache mod_passenger.

Además, vamos a instalar dos herramientas que simplifican la instalación y el mantenimiento de Ruby: ruby-install para la instalación y chruby para cambiar fácilmente entre versiones.

Instalar ruby-install y Ruby

En primer lugar, vamos a asegurarnos de que tenemos todas las librerías necesarias para compilar

sudo apt-get install build-essential

Tras ello seguimos las instrucciones de https://github.com/postmodern/ruby-install#install

cd /tmp
wget -O ruby-install-0.5.0.tar.gz https://github.com/postmodern/ruby-install/archive/v0.5.0.tar.gz
tar -xzvf ruby-install-0.5.0.tar.gz
cd ruby-install-0.5.0/
sudo make install

Verificamos que está correctamente instalado con “ruby-install -V”:

ruby-install -V
ruby-install: 0.5.0

Y procedemos a instalar la versión deseada de Ruby. En este caso, queremos instalar Ruby 2.1.3.

$ ruby-install ruby 1.9.3
Installing ruby 2.1.3 into /home/$USER/.rubies/ruby-2.1.3 ...
Installing dependencies for ruby 2.1.3 ...
[sudo] password for $USER:
...

Este proceso va a instalar las dependencias, descargar las fuentes de Ruby 2.1.3. y lo compilará, por lo que tardará un rato. Cuando termine mostrará la ruta del binario:

>>> Successfully installed ruby 2.1.3-p242 into /home/$YSER/.rubies/ruby-2.1.3...

Instalar chruby y configurar el cambio automático de versión

Aunque ya hemos instalado Ruby 2.1.3, nos falta especificar que ésta es la versión por defecto que queremos usar. Además, queremos poder cambiar entre versiones de manera sencilla. Para ello, hay que instalar chruby siguiendo las instrucciones de https://github.com/postmodern/chruby#install . Esta herramienta cumple los requisitos descritos y además permite cambiar automáticamente de versión en función del directorio en el que nos encontremos (muy útil si desarrollamos varias aplicaciones en el mismo equipo).

cd /tmp
wget -O chruby-0.3.9.tar.gz https://github.com/postmodern/chruby/archive/v0.3.9.tar.gz
tar -xzvf chruby-0.3.9.tar.gz
cd chruby-0.3.9/
sudo make install

Una vez instalado, chruby nos permite elegir la versión de ruby que queremos usar de entre todas aquellas que tenemos instaladas. En este ejemplo sólo tenemos una única aplicación Ruby On Rails que usa ruby 2.1.3, basta con añadir estas lineas a /home/$USER/.bashrc:

source /usr/local/share/chruby/chruby.sh
chruby ruby 2.1.3.

Tras ello, cerramos la terminal, volvemos a entrar comprobamos que chruby está cargado y funciona correctamente:

user@host:~$ chruby
   ruby-2.1.3.
user@host:~$ ruby -v
ruby 2.1.3p242 (2014-09-19 revision 47630) [x86_64-linux]

Una vez instaladas varias versiones, para cambiar la versión utilizada en el directorio en el que nos encontramos basta con hacer:

chruby ruby VERSION

Bonus: Hacer que la versión cambie automáticamente en función del directorio

Es posible que tengamos más de un proyecto Ruby On Rails y queramos utilizar versiones diferentes de Ruby en cada proyecto. Suponiendo instaladas dos versiones (por ejemplo, Ruby 1.9.3. y Ruby 2.1.3), se puede cambiar manualmente de versión usando chruby. Por ejemplo, vamos a suponer que tenemos dos proyectos:

  • /opt/proyecto1, con Ruby 1.9.3
  • /opt/proyecto2, con Ruby 2.1.3

Vamos a comprobar que tenemos ambas versiones de Ruby instaladas:

$ chruby
  ruby-1.9.3-p547
 * ruby-2.1.3

Para configurar el cambio automático, hay que insertar las lineas siguientes a /home/$USER/.bashrc, sustituyendo las insertadas anteriormente:

source /usr/local/share/chruby/chruby.sh
source /usr/local/share/chruby/auto.sh

Y a continuación, crear un archivo “.ruby-version” en cada directorio, especificando en él la versión deseada:

echo "ruby-1.9.3" > /opt/proyecto1/.ruby-version
echo "ruby-2.1.3" > /opt/proyecto2/.ruby-version

Tras ello, comprobamos que en cada directorio se invoca la versión correcta:

$ cd /opt/proyecto1/
$ ruby -v
ruby 1.9.3p547 (2014-05-14) [x86_64-linux]
$ cd /opt/proyecto2/
ruby -v
ruby 2.1.3p242 (2014-09-19 revision 47630) [x86_64-linux]

Instalar Rails y Bundler

Una vez instalada la versión de Ruby deseada, vamos a proceder a instalar las gemas Rails (framework MVC) y Bundler (asistente para la gestión de gemas). Para ello:

$ gem install bundler
Successfully installed bundler-1.7.11
Parsing documentation for bundler-1.7.11
Done installing documentation for bundler after 1 seconds
1 gem installed

Bundler no dio problemas, sin embargo al instalar Rails obtuve el siguiente error:

$ gem install rails
Building native extensions.  This could take a while...
ERROR:  Error installing rails:
	ERROR: Failed to build gem native extension.

    /home/areig/.rubies/ruby-2.1.3/bin/ruby extconf.rb
/home/areig/.rubies/ruby-2.1.3/bin/ruby: invalid option -2  (-h will show valid options) (RuntimeError)

extconf failed, exit code 1

El error viene al instalar la gema “nokogiri”, que es una dependencia de Rails. Para solucionarlo, installé las siguientes libreras y volví a instalar la gema especificando que utilice las libreras del sistema:

$ sudo apt-get install libxslt-dev libxml2-dev libxml2
$ gem install nokogiri -- --use-system-libraries
Building native extensions with: '--use-system-libraries'
This could take a while...
Successfully installed nokogiri-1.6.5
Parsing documentation for nokogiri-1.6.5
Installing ri documentation for nokogiri-1.6.5
Done installing documentation for nokogiri after 2 seconds
1 gem installed

Tras ello, pude instalar la gema “rails” sin problemas”.

Instalar otras gemas de la aplicación

Para instalar el resto de las gemas requeridas por la aplicación que queramos desplegar, basta con navegar hasta el directorio raíz y utilizar bundler:

bundle install
bundle update

Puede ser que la instalación de alguna gema falle, en ese caso es necesario investigar el error antes de continuar. Normalmente la solución pasa por instalar librerías o herramientas necesarias, como libsqlite3-dev o nodejs.

Tras ello, podemos comprobar que todas las gemas necesarias están correctamente instaladas utilizando el servidor embebido de rails y navegando a http://localhost:3000

$ rails s
=> Booting WEBrick
=> Rails 4.2.0 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2015-01-07 17:21:31] INFO  WEBrick 1.3.1
[2015-01-07 17:21:31] INFO  ruby 2.1.3 (2014-09-19) [x86_64-linux]
[2015-01-07 17:21:31] INFO  WEBrick::HTTPServer#start: pid=22394 port=3000

Instalar passenger y configurar Apache

Como servidor de aplicaciones vamos a utilizar Passenger. Para ello, basta con instalar la gema:

gem install passenger

Tras ello, hay que instalar el módulo de Apache que conecta con Passenger. Para ello, hay que ejecutar:

passenger-install-apache2-module

Cuando nos pregunte por el lenguaje a utilizar seleccionar sólo Ruby.

Cuando finalice, el instalador nos dará las líneas que hay que incluir en el VirtualHost de Apache para cargar la configuración:

   LoadModule passenger_module /home/$USER/.gem/ruby/2.1.3/gems/passenger-4.0.57/buildout/apache2/mod_passenger.so
   <IfModule mod_passenger.c>
     PassengerRoot /home/$USER/.gem/ruby/2.1.3/gems/passenger-4.0.57
     PassengerDefaultRuby /home/$USER/.rubies/ruby-2.1.3/bin/ruby
   </IfModule>

De modo que el VirtualHost podría quedar así:

<VirtualHost *:443>
        ServerName XXXX
        ServerAlias XXXXX
        ErrorLog /var/log/apache2/XXX-error.log
        CustomLog /var/log/apache2/XXX.log Common
        LimitRequestFieldSize 20000

        //Lineas de SSL
        LoadModule passenger_module /home/$USER/.gem/ruby/2.1.3/gems/passenger-4.0.57/buildout/apache2/mod_passenger.so
        <IfModule mod_passenger.c>
     		PassengerRoot /home/$USER/.gem/ruby/2.1.3/gems/passenger-4.0.57
     		PassengerDefaultRuby /home/$USER/.rubies/ruby-2.1.3/bin/ruby
	</IfModule

        <Directory /var/www/CONTEXTO_DE_LA_APLICACION>
                AllowOverride All
                Options +Indexes +ExecCGI +FollowSymLinks -Multiviews
                Require all granted
                RailsBaseURI /CONTEXTO_DE_LA_APLICACION
        </Directory>

</VirtualHost>

Con ello tenemos una base sobre la que desplegar nuestras aplicaciones Ruby On Rails. Si bien la instalación es un poco farragosa, en mi experiencia esta configuración no nos ha dado problemas una vez en producción.

Publicado en proyectos Etiquetado con: , ,

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*