post thumbnail

Sinatra desde Cero: Estructura de proyecto

Publicado Por: Alberto Grespan, El 05/12/2013


Detalles del Curso:

Dificultad: Aprendiz

Duración: 30 min


La serie de Sinatra desde Cero, buscará otorgarte el conocimiento necesario para que puedas desarrollar tus propias aplicaciones Web haciendo uso de esta magnifica herramienta.

En este octavo capítulo empezaremos a estructurar una aplicación de manera modular un poco más compleja que lo realizado la semana anterior y haciendo funcionar dichos módulos como middleware en Sinatra.

Para comprender correctamente todo lo que hablaremos en esta serie, es conveniente tener un conocimiento básico sobre el lenguaje de Ruby. Podrás conseguir toda la información desees aquí


Estructura de proyecto

Deben recordar que en múltiples ocasiones hemos dicho que Sinatra nos da la completa libertad de ensamblar las aplicaciones como nosotros queramos. Esto ciertamente es muy bueno (para algunos) pero a su misma vez muy confuso (para otros), ya que no hay una "mejor forma" de hacer las aplicaciones sino que todas son buenas. Es en este punto donde empezamos a leer por internet las mil y un distintas formas para ensamblar una aplicación web en Sinatra "correctamente"; pero la pregunta del millón es:

¿Qué es lo que realmente necesitamos?

Ciertamente, casi todos nosotros tendemos a complicar demasiado las cosas en un punto muy temprano del desarrollo cuando en realidad deberíamos fijar las metas a lograr para poder realizarlo de la manera más sencilla posible e ir ajustando en el proceso. Es aquí cuando surge una nueva interrogante:

¿Por qué no realizamos la aplicación de manera convencional/clásica (sencilla)?

La respuesta es simple, si de antemano conocemos que la aplicación final será bastante reducida en tamaño, tranquilamente podemos iniciar con este modelo de aplicación sin tener que pensarlo demasiado. Por el contrario, si conocemos que será de un tamaño final medio/grande, quizás, como recomendación, evaluar si es mejor ir a algo un poco más estructurado como Rails. La misión al realizar aplicaciones grandes siempre será poder reutilizar componentes para hacerla los más DRY que podamos y esto nos obliga de cierto modo a que la aplicación sea modular donde los componentes o módulos de la aplicación sean middleware. Esto de cierta forma es lo que hicimos en el capítulo anterior cuando hablamos de Subclases.

Para continuar con el tema y reafirmar el conocimiento de la semana pasada pero agregándole cierta complejidad; hoy realizaremos una muy pequeña aplicación modular con estructura similar a la de Ruby on Rails (MVC) pero sin los modelos por ahora.

Estructura

$ tree .
.
├── app
│   ├── controllers
│   │   ├── application_controller.rb
│   │   └── users_controller.rb
│   ├── helpers
│   │   └── application_helper.rb
│   └── views
│       ├── users.erb
│       ├── layout.erb
│       └── not_found.erb
└── config.ru
  • En los controladores tenemos el application_controller que viene siendo nuestro controlador principal y de donde heredarán todos los demás controladores de la aplicación. El users_controller que contiene las rutas de la aplicación relacionadas con los usuarios.

  • Los helpers vienen siendo clases que contienen fragmentos de código reusables y asisten en funcionalidad a los controladores y vistas.

  • Las vistas son los archivos referentes a las distintas pantallas de presentación que ve el usuario y que pueda tener nuestra aplicación.

  • config.ru nombre por convención del archivo utilizado por el servidor web de Ruby: Rack.

Echemos un vistazo al contenido de dichos archivos.

# application_helper.rb

module ApplicationHelper
  def title(value = nil)
    @title = value if value
    @title ? "#{@title}" : "Título por defecto"
  end
end

El application_helper: es el "helper" principal de la aplicación, se encuentra dentro de un módulo y está encargado de establecer un título a las páginas html que se encuentran dentro de la carpeta de las vistas.

# application_controller.rb

class ApplicationController < Sinatra::Base
  helpers ApplicationHelper

  # establece la carpeta de vistas a ../views.
  set :views, File.expand_path('../../views', __FILE__)

  # despliega las páginas 404
  not_found do
    title 'Not Found!'
    erb :not_found
  end
end

Por lo que podemos ver en el archivo application_controller al ser el controlador principal de Sinatra hereda de Sinatra::Base incluye el helper ApplicationHelper que se encuentra en la carpeta de helpers, establece la ruta de donde se encontrarán las vistas y contiene el manejo de errores para las páginas 404.

# users_controller.rb

class UsersController < ApplicationController
  get '/' do
    title "Usuarios"
    erb :users
  end

  get '/:number' do
    title "Usuario #{params[:number]}"
    erb :users
  end
end

Aquí podemos ver que users_controller es un controlador que hereda de application_controller y a su vez contiene dos rutas de tipo get donde les establece los títulos a dichas páginas y utiliza la vista users.

# layout.erb

<html>
  <head>
    <title><%= title %></title>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

Este es el esqueleto HTML principal de la aplicación; es reusable por el resto de las vistas de la aplicación con la finalidad de no repetir siempre lo mismo. Cuando creamos otra vista se inyectará su contenido dentro de la etiqueta <%= yield %>. se pueden crear distintos tipos de esqueletos predefinidos pero cuando se deseen utilizar se le debe indicar a Sinatra manualmente cual es el que se debe usar erb :users, :layout => :otro_layout

# users.erb

Página de usuarios!

Este archivo al igual que el not_found.erb solo contienen texto.

# config.ru

require 'sinatra/base'
Dir.glob('./app/{helpers,controllers}/*.rb').each { |file| require file }

map("/users") { run UsersController }
map("/")        { run ApplicationController }

Por último y para mi, el más importante del post es el archivo config.ru, ya que es aquí donde Sinatra genera nuestra aplicación. Primero un require 'sinatra/base para crear nuestra aplicación modular; segundo por medio del uso de Dir.glob se realiza un require de cada uno de los archivos que contenga extensión .rb, y por último se agregan los módulos cómo middleware, definiendo lo siguiente:

  • Todas las rutas que se encuentran dentro del controlador users_controller.rb se verán precedidas por el slug users.
  • La ruta principal de la aplicación relacionada con application_controller.rb no está haciendo nada particular, únicamente nos desplegará la página 404 como ejemplo.

Hagamos una prueba de nuestra pequeña aplicación.

$ rackup -p 3000

$ curl --request GET localhost:3000
<html>
  <head>
    <title>Not Found!</title>
  </head>
  <body>
    La página no existe 404!
  </body>
</html>

Aquí podemos apreciar que al acceder por una ruta que no existe dentro de nuestra aplicación la misma nos arroja la vista not_found.erb que se encuentra definida en application_controller.

Ahora probemos las rutas de /users:

$ curl --request GET localhost:3000/users
<html>
  <head>
    <title>Usuarios</title>
  </head>
  <body>
    Página de usuarios!
  </body>
</html>

$ curl --request GET localhost:3000/users/1
<html>
  <head>
    <title>Usuario 1</title>
  </head>
  <body>
    Página de usuarios!
  </body>
</html>

A diferencia de la anterior observamos que efectivamente ambas rutas de users_controller.rb están precedidas por el slug users aunque dichas rutas no estén escritas así dentro del controlador. La semana entrante veremos otras maneras existentes para agregar middleware y realizar el enrutamiento a nuestra aplicación en Siantra.


Conclusión

En este octavo capítulo, hemos empezado a atar los cabos sueltos que tenemos de capítulos anteriores; aprendiendo a estructurar una aplicación en Sinatra de manera modular asemejando la estructura de una aplicación Rails y a su vez hemos puesto a prueba una primera parte de enrutamiento en base a middleware el cual expandiremos la próxima semana. Si te surge algún tipo de duda no te detengas y déjanos un comentario, que gustosamente lo responderemos.

¡Hasta el próximo capítulo!


¿Te ha gustado esta publicación?

Compártela:

Por Alberto Grespan

Conoce más sobre este autor aquí


comments powered by Disqus