# Rails sostenible (IV): rutas y plantillas HTML

*Cuarta entrega de la serie **[Rails sostenible](/search?tag=rails-sostenible)**, sobre **Sustainable Web Development with Ruby on Rails** de David Bryant Copeland. Tiempo de lectura estimado: 12 minutos.*

Con el [seam de la lógica de negocio](/post/rails-sostenible-iii-logica-de-negocio-fuera-de-active-record) ya claro, el libro empieza a recorrer las capas de Rails de fuera hacia dentro. Y lo primero que encuentra toda petición es el enrutado. Copeland tiene opiniones muy firmes sobre rutas, y casi todas se reducen a una: **no te pelees con las convenciones de Rails, abrázalas**.

## Usa siempre rutas canónicas

La primera regla es no inventar. Rails te da un sistema RESTful con siete acciones por recurso (`index`, `show`, `new`, `create`, `edit`, `update`, `destroy`), y Copeland te pide que te ciñas a él:

```ruby
# config/routes.rb
resources :customers
```

¿Por qué tanto énfasis en lo canónico? Porque las rutas estándar son **predecibles**. Cualquiera que conozca Rails sabe, sin mirar tu código, que `GET /customers/5` va a `CustomersController#show`. Esa predictibilidad es sostenibilidad pura: reduce la carga cognitiva de cada persona que llega al proyecto. Cuanto más exótica sea tu tabla de rutas, más arqueología tendrá que hacer alguien para entenderla.

## No declares rutas que no usas

Un detalle pequeño con impacto real: `resources :customers` genera las siete rutas, aunque solo sirvas dos. Copeland recomienda declarar **solo lo que de verdad existe**:

```ruby
resources :customers, only: [:index, :show]
resources :sessions, only: [:new, :create, :destroy]
```

Cada ruta declarada es una promesa: "esta URL hace algo". Declarar rutas fantasma que devuelven errores o, peor, que existen "por si acaso" es carrying cost. Además, una tabla de rutas que refleja exactamente lo que la app hace es documentación viva: `bin/rails routes` te cuenta la verdad.

## URLs bonitas: que redirijan a la canónica

A veces quieres una URL de marketing, corta y memorable (`/premium`). Copeland no se opone, pero pide que esas *vanity URLs* **redirijan** a la ruta canónica en lugar de duplicar lógica:

```ruby
get "/premium", to: redirect("/plans/premium")
```

Así solo hay un sitio donde vive la página de verdad. La URL bonita es un alias, no una copia. (Este blog hace algo parecido con el campo `aliases` del front matter: slugs alternativos que redirigen al canónico.)

![Código CSS en la pantalla](fig-01.webp)

## No crees acciones custom: crea más recursos

Esta es, para mí, la idea más potente del capítulo y la que más cambia la forma de diseñar. La tentación natural cuando necesitas "una acción que no es CRUD" es añadir un miembro custom:

```ruby
# La tentación
resources :orders do
  member do
    post :cancel   # POST /orders/:id/cancel -> OrdersController#cancel
  end
end
```

Copeland dice: para. En vez de añadir un verbo custom a un recurso existente, **modela un recurso nuevo**. Cancelar un pedido no es una acción rara de `Order`: es la *creación* de una cancelación.

```ruby
# La forma sostenible
resources :orders, only: [:index, :show] do
  resource :cancellation, only: [:create], module: :orders
end
# POST /orders/:id/cancellation -> Orders::CancellationsController#create
```

¿Por qué es mejor? Porque te devuelve a las siete acciones canónicas, que ya sabes manejar. El `CancellationsController` tiene un `create` normal y corriente que delega en tu lógica de negocio. No hay acciones especiales que testear de forma especial, no hay un controlador con quince métodos. Cada vez que sientas la necesidad de un verbo custom, pregúntate: *¿qué sustantivo estoy creando, actualizando o destruyendo en realidad?* Casi siempre hay un recurso escondido.

## Rutas anidadas, con estrategia

El anidamiento (`resources :a do resources :b end`) es útil para expresar contención real, pero se desmadra rápido. Copeland recomienda **anidar como mucho un nivel** y solo cuando la relación padre-hijo importe para la URL. Para todo lo demás, recursos planos o con `shallow: true`. URLs como `/a/1/b/2/c/3/d/4` son un olor a diseño que se fue de las manos.

## HTML semántico

Pasando a las plantillas, Copeland insiste en algo que en este blog defiendo mucho: usar **HTML semántico**. Nada de `<div>` para todo. Usa `<header>`, `<nav>`, `<main>`, `<article>`, `<aside>`, `<footer>`, `<button>` para botones y `<a>` para enlaces. El HTML semántico es la base de la accesibilidad, mejora el SEO y, sobre todo, comunica intención: un `<nav>` dice "esto es navegación" a los lectores de pantalla, a los buscadores y al siguiente programador.

## Idealmente, una variable de instancia por acción

Aquí viene un consejo afilado. Cada `@variable` que un controlador expone a la vista es **acoplamiento**: la vista pasa a depender de ese nombre y de ese tipo. Cuantas más ivars, más frágil la relación controlador-vista. Copeland propone tender hacia **una sola variable de instancia por acción**, idealmente un objeto que represente todo lo que la página necesita:

```ruby
def show
  @page = Customers::ShowPage.new(customer: Customer.find(params[:id]))
end
```

```erb
<h1><%= @page.customer_name %></h1>
<p>Pedidos: <%= @page.order_count %></p>
```

No siempre es práctico llegar a una sola, pero la dirección es clara: menos ivars sueltas, más un punto de entrada cohesivo. La vista pregunta a un objeto bien definido en lugar de hurgar en cinco variables independientes.

## Los partials son componentes reutilizables

Copeland pide tratar los partials como **componentes con interfaz explícita**, pasando siempre `locals` en lugar de depender de variables de instancia heredadas del contexto:

```erb
<%# Mal: el partial depende mágicamente de @customer del contexto %>
<%= render "customer_card" %>

<%# Bien: interfaz explícita, reutilizable en cualquier sitio %>
<%= render "customer_card", customer: @page.customer %>
```

Un partial que recibe sus datos por `locals` es como una función con argumentos: puedes razonar sobre él en aislamiento y reutilizarlo sin sorpresas. Un partial que lee `@customer` del aire solo funciona en el contexto donde esa ivar existe, y rastrear de dónde sale es una pesadilla. Rails moderno incluso permite declarar los locals esperados con `<%# locals: (customer:) %>`, formalizando ese contrato.

## Simplemente usa ERB

El capítulo se cierra con una defensa de ERB frente a Haml, Slim y compañía. El argumento es de sostenibilidad: ERB es **HTML con Ruby incrustado**. Todo el mundo sabe HTML, el tooling lo soporta de serie, cualquier desarrollador nuevo lo lee sin aprender una sintaxis indentada propia. Las alternativas ahorran unas llaves a costa de añadir una dependencia, una curva de aprendizaje y un punto de fricción para cada persona futura.

> Elegir Haml para ahorrarte escribir `<div>` es pagar un carrying cost permanente por una comodidad de tecleo momentánea.

No es que las alternativas sean malas; es que el ahorro no compensa el coste a lo largo de los años. ERB es la opción aburrida, y aburrido —en sostenibilidad— es un cumplido.

## Mi versión

Lo de "crea más recursos en vez de acciones custom" me costó interiorizarlo, pero una vez que haces el clic, no hay vuelta atrás. Antes mis controladores se llenaban de `approve`, `publish`, `archive`, `reactivate`... y cada uno era un método especial con su propio testeo y sus propias rarezas. Ahora pienso en sustantivos: una publicación es `POST /posts/:id/publication`, un archivado es la creación de un `Archival`. Los controladores vuelven a ser aburridos y todos se parecen. Aburrido = mantenible.

Sobre ERB, suscribo cada palabra. He heredado proyectos en Slim donde, para tocar una plantilla, primero tenías que recordar la sintaxis. Multiplica eso por cada persona que pasa por el proyecto en cinco años y el ahorro de teclas sale carísimo. En mis proyectos, plantillas en el lenguaje del propio medio (HTML) y punto.

Donde soy menos purista que el libro es en lo de "una sola variable de instancia". Me parece una dirección sanísima, pero forzarla siempre puede llevar a objetos *page* artificiales. Tiendo a ello cuando la vista es compleja y dejo dos o tres ivars cuando la acción es trivial.

## Lo que viene

Ya tenemos las rutas limpias y las plantillas bien estructuradas. En el **próximo post** seguimos en la capa de presentación pero entramos en terreno polémico: **helpers, CSS y minimizar JavaScript**. Veremos dónde va de verdad la lógica de vista, por qué Copeland recela de presenters y decorators, cómo adoptar un design system y, sobre todo, su defensa de hacer el mínimo JavaScript posible apoyándose en vistas renderizadas en servidor y en Turbo.
