En noviembre de 2022 vio la luz The Rails Foundation, una fundación cuya misión es mejorar la documentación, educación, marketing y eventos del framework Ruby on Rails. Esta noticia es crucial para el futuro del framework, ya que técnicamente no ha parado de evolucionar, pero el ecosistema no ha acompañado.

Muchos desarrolladores amamos Ruby on Rails, pero en nuestros trabajos programamos en otros lenguajes y otros frameworks… ¿por qué? Porque le falta ecosistema. Aprovechando el lanzamiento de la fundación, he decidido aportar mi granito de arena para apoyar la difusión de Rails escribiendo sobre cómo despegar Rails en Google Cloud.

Hace unos años desplegar un proyecto en Ruby on Rails sobre el serverless de GCP era misión casi imposible y, aunque funcionara, cualquier persona con dos dedos de frente no votaría para poner algo así en producción. Hoy en día, por suerte, desplegar en Cloud Run es cuestión de pocos minutos y, encima, mucho más robusto. Para darle un poco más de gracia al post voy a usar MongoDB en su versión gestionada (Mongo Atlas) de forma que podamos tener nuestros proyectos Rails dentro de la capa free de GCP y Mongo. ¿Listos?

La aplicación a desplegar es un crud simple llamado Santa Rita, que nos permite escribir nuestras opiniones: Santa Rita Rita, lo que se escribe no se quita (o sí). Más adelante ya modificaremos nuestra app para que realmente no se puedan cambiar ni borrar las opiniones, pero en este post vamos a centrarnos en subir una primera versión a Cloud Run.

¿Qué es Ruby on Rails?

Ruby on Rails es un framework de desarrollo de apps modernas que minimiza la complejidad, fomenta la productividad y hace divertido el desarrollo de aplicaciones ya sea un ‘hola mundo’ o una aplicación monstruosamente grande. Rais es un framework opinado, lo que quiere decir que considera una manera buena de hacer las cosas y las implementa; al contrario de otros, como Express, que optan por que sea el desarrollador el que monte todo a mano o mediante componentes. Si programas en Rails, tiene que ser en “the rails way”. Lo bueno es que si aprendes a usarla, verás tu productividad aumentar de manera sorprendente.

Para lograr esto, se basa en dos principios:

Ruby on Rails va por su versión 7 y ya lleva más de 20 años con nosotros. Grandes compañías confían en Rails como Basecamp, Github, Shopify, Twitch o Cookpad.

Hacer aplicaciones en Rails es rápido y divertido, pero es necesario estudiar su forma de hacer las cosas para poder trabajar con él sin la sensación de que todo es magia fuera de tu control: ORM, migraciones, tests unitarios, MVC, renderización de vistas… Hay un montón de cosas chulas que estudiar para poder sacarle partido.

MongoDB, una base de datos diferente

MongoDB es la primera opción que suele venir a nuestra cabeza cuando hablamos de bases de datos documentales (no relacionales). Rails viene con todo configurado de serie incluyendo un ORM para una base de datos relacional, preferiblemente postgreSQL. Con un ORM podemos interactuar con la base de datos a más alto nivel que con queries, otros ORM famosos son Hibernate(Java), sqlalchemy(python) o Sequelize(node). Para este proyecto hemos decidido usar MongoDB por lo que tendremos que hacer algunas modificaciones para que eso suceda.

Nota importante: que venga por defecto algo no significa que no podamos modificarlo. Para este ejemplo vamos a quitar el ORM llamado active record y para sustituirlo usaremos mongoid, el ODM (Object Document Mapper) de Ruby para Mongodb.

Cloud Run

Google Cloud Run es un servicio de ejecución de contenedores serverless que nos permite ejecutar aplicaciones stateless de manera moderna, escalable y robusta. Siendo uno de los principales servicios de Google cuenta con gran cantidad de características (autoescalado desde cero, monitorización, controles de networking de entrada y salida…) e integraciones (con Cloud Build, Secret manager, Memorystore…). Desplegar en Cloud Run es sinónimo de pocos problemas y grandes alegrías.

Paso 1. Requisitos iniciales, preparando el entorno

Lo primero que vamos a necesitar es tener un proyecto en la consola de Google Cloud con permisos de owner (hacen falta muchos menos permisos, pero optamos por la simplicidad) y las siguientes APISs habilitadas:

Lo segundo que necesitamos es un cluster MongoDB en Mongo Atlas. Configurarlo es muy sencillo y dispone de entornos free para pruebas y sandbox. Una vez configurado, no costará llegar mucho hasta el sitio donde nos dan la url de conexión para Ruby con un formato similar a este:

mongodb+srv://josetcalleja:misecreto@cluster0.dafddsaf.mongodb.net/?retryWrites=true&w=majority

Donde josetcalleja es el usuario, misecreto es el pass y cluster0.dafddsaf.mongodb.net es el host de nuestro cluster.

Otro requisito para que todo esto funciones será el aceptar las conexiones entrantes desde cualquier IP con una regla de alow 0.0.0.0/0 (tendré que hacer post otro contando cómo mejorar la seguridad de acceso 🤓).

Por último necesitamos tener instalado en nuestro ordenador Ruby versión 2.7.1. Para poder instalar Rails con el siguiente comando:

gem install rails

Si todo ha salido bien veremos en nuestra consola algo como: Successfully installed rails-7.0.4

Paso 2. Creando nuestra aplicación y configurando mongoid

Crear una aplicación con Rails es tan sencillo como:

rails new santarita --skip-active-record

Pongamos atención al parámetro de no instalar el active record. Usaremos mongoid en su lugar.

Veremos que nos ha creado un montonazo de carpetas y ficheros en nuestra carpeta santarita. Como dijimos anteriormente, Rails nos ofrece un set completo de soluciones ya implementas, todo sin repetirse y en un único lugar.

Lo primero que vamos a hacer es añadir una línea al fichero Gemfile, en este fichero están todas las gemas (dependencias en Ruby) necesarias para nuestra aplicación. Lo único que tenemos que añadir es la gema necesaria para conectarnos a nuestra base de datos MongoDB. Donde añadimos la línea no es importante.

gem "mongoid"

Una vez salvado el fichero Gemfile ejecutamos el comando para instalar las nuevas dependencias:

Bundle install

Una vez instalada la gema llega el momento de la configuración. Por suerte, la gema cuenta con un script para generar el fichero, tampoco es mucha suerte porque luego veremos que el fichero lo cambiamos bastante 😂.

rails g mongoid:config

En el fichero vamos a configurar los datos de nuestra conexión mongo Atlas para nuestra aplicación, pondremos los datos para desarrollo y producción.

config/mongoid.yml:

development:
 clients:
   default:
     uri: mongodb+srv://jtparadigma:ntBaMdfa89fsd@cluster0.d3j5xvy.mongodb.net/mongoblog_development?retryWrites=true&w=majority
     options:
       server_selection_timeout: 5  
production:
 clients:
   default:
     uri: mongodb+srv://jtparadigma:ntBaMdfa89fsd@cluster0.d6j5xvy.mongodb.net/mongoblog_production?retryWrites=true&w=majority
     options:
       server_selection_timeout: 5

Paso 3. Scaffoldeando, la manera rápida de crear todo lo necesario

Los generadores en Rails nos permiten crear ficheros de manera rápida y con bastante del contenido necesario. Rails dispone de gran cantidad de generadores: para modelos, vistas, assets… pero sin duda el más completo es el scaffold, que nos permite crear un modelo con su controlador y vistas usando solo un comando, ¿qué os parece? Utilizaremos el siguiente comando para crear la entidad post con su título, su autor y su contenido, recordemos que la aplicación vale para decir nuestras opiniones y que luego no puedan ser modificadas.

rails g scaffold Post title:string author:string body:text

Mirando el terminal nos podemos hacer una idea de los ficheros que nos ha creado por nosotros el siempre servicial generador Scallfold.

Creo que ha llegado el momento de ver que todo está correcto y nuestra app por lo menos arranca, iniciamos el servidor de la app en modo desarrollo con el comando:

rails s

Si vamos en nuestro navegador a http://127.0.0.1:3000 podemos ver nuestra app funcionando, de momento solo es información de Rails, pero es un principio.

Cuando hemos generado los posts, Rails ya se ha encargado de añadirnos las rutas necesarias para el CRUD de los post. Para ver el índice de los posts solo tenemos que añadir /posts a la url de antes.

Ahora nuestra aplicación muestra una espartana vista con un botón de new post que nos lleva a un formulario y luego a un listado con opciones de editar y borrar. Bastante impresionante considerando que solo hemos tenido que teclear un comando.

Paso 4. Desplegando en Cloud Run

Cloud Run nos permite desplegar contenedores de manera sencilla. Para poder desplegar la app vamos a necesitar un Dockerfile (sacado del quickstart de la documentación oficial de Google Cloud) con la información necesaria para la generación de la imagen del contenedor:

# Use the official Ruby image from Docker Hub
# https://hub.docker.com/_/ruby

# [START cloudrun_rails_base_image]
# Pinning the OS to buster because the nodejs install script is buster-specific.
# Be sure to update the nodejs install command if the base image OS is updated.
FROM ruby:2.7.1-buster
# [END cloudrun_rails_base_image]

RUN (curl -sS https://deb.nodesource.com/gpgkey/nodesource.gpg.key | gpg --dearmor | apt-key add -) && \
   echo "deb https://deb.nodesource.com/node_14.x buster main"      > /etc/apt/sources.list.d/nodesource.list && \
   apt-get update && apt-get install -y nodejs lsb-release

RUN (curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -) && \
   echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
   apt-get update && apt-get install -y yarn

WORKDIR /app

# Application dependencies
COPY Gemfile Gemfile.lock ./

RUN gem install bundler && \
   bundle config set --local deployment 'true' && \
   bundle config set --local without 'development test' && \
   bundle install

# Copy application code to the container image
COPY . /app

ENV RAILS_ENV=production
ENV RAILS_SERVE_STATIC_FILES=true
# Redirect Rails log to STDOUT for Cloud Run to capture
ENV RAILS_LOG_TO_STDOUT=true
# [START cloudrun_rails_dockerfile_key]
ARG MASTER_KEY
# TODO: SUSTITUIR POR LA CLAVE DEL FICHERO CONFIG/MASTER.KEY
ENV RAILS_MASTER_KEY=4b45265824b3c08989090
# [END cloudrun_rails_dockerfile_key]

# pre-compile Rails assets with master key
RUN bundle exec rake assets:precompile

EXPOSE 8080
CMD ["bin/rails", "server", "-b", "0.0.0.0", "-p", "8080"]

Con nuestro fichero listo ya podemos ejecutar el comando de despliegue de Cloud Run, el cual nos pedirá datos como dónde está el código a subir (carpeta actual por defecto), el nombre del servicio (nombre de la carpeta por defecto) y si queremos que se puede llamar al servicio sin autenticación (le diremos que sí, por defecto es no). El sdk de Google Cloud se encargará de generar la imagen, crear el servicio y enrutar el tráfico al mismo.

Después de unos minutos la consola nos indicará que el servicio se ha creado correctamente mostrándonos una url a la que ir.

La mala noticia es que la web nos muestra un error en lugar de la flamante web que enseñaba en desarrollo. La buena es que esto está diseñado así y en producción no te muestra la página por defecto. Añadir /posts a la url hará la magia necesaria para ver nuestra aplicación Ruby on Rails desplegada correctamente en Cloud Run y conectada a nuestro MongoDB.

Paso 5. Últimos retoques

Para terminar nuestra flamante aplicación solo nos queda configurar la app para que la web de inicio sea /posts.

Toda la configuración de rutas se almacena en el fichero config/routes.rb, el scaffold antes ejecutado nos ha añadido resources :posts que nos crea todas las rutas necesarias para el CRUD de Posts que usamos. Para indicarle la vista inicial necesitamos añadir:

root "posts#index"

El servidor de desarrollo nos muestra que la vista inicial ha desaparecido y nos muestra en su lugar el índice de posts.

Ya solo nos queda volver a ejecutar el comando de despliegue para subir nuestra nueva versión y verla funcionando correctamente 🎉.

Conclusiones

Desplegar una aplicación Ruby on Rails es supersencillo y rápido en Cloud Run, basta con configurar el Dockerfile y ejecutar el comando de deploy. Gracias a la filosofía de Rails, desarrollar aplicaciones se vuelve una tarea mucho más gratificante al obtener resultados visibles sin tener que volvernos locos configurando ficheros y addons.

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.