Nivel inicial6 min de lectura · Publicado el

Resource o recursos en Rails: CRUD con scaffold

Recursos en Rails: resources :courses crea siete rutas, con su verbo HTTP, su ruta y su acción, de index a destroy resources: 1 línea, 7 rutasrubentejera.com resources :courses7 rutasGET/coursesindexGET/courses/:idshowGET/courses/newnewPOST/coursescreateGET/courses/:id/editeditPATCH/courses/:idupdateDELETE/courses/:iddestroy
Una sola línea en config/routes.rb abre las siete rutas del CRUD de un recurso. Puedes verlas con bin/rails routes -c courses; update responde también a PUT.

Un recurso (resource) en Rails es un elemento sobre el que puedes hacer un CRUD: Create, Read, Update, Destroy (crear, leer, actualizar y borrar). Un curso, un usuario o un coche son recursos.

Con un curso, por ejemplo, puedes darlo de alta, consultarlo, corregir sus datos o darlo de baja. Rails reparte ese trabajo entre tres piezas, el modelo, la vista y el controlador (el patrón MVC), y te deja generarlas a mano o de golpe con un scaffold (en inglés, «andamio»).

Crear un recurso con scaffold

  1. Genera el recurso.
  2. Crea la tabla en la base de datos.
  3. Arranca el servidor y ábrelo en el navegador.

1. Genera el recurso

bin/rails generate scaffold NombreRecurso atributo:tipo

Por ejemplo, un curso con título:

bin/rails generate scaffold Course title:string

2. Crea la tabla

El scaffold genera una migración, un fichero que describe la tabla courses. Para aplicarla:

bin/rails db:migrate

Tienes más detalle en Migraciones en Ruby on Rails.

3. Arranca el servidor

bin/rails server

Y abre localhost:3000/courses en el navegador. Al principio la lista está vacía:

Página localhost:3000/courses generada por el scaffold: título Courses, columna Title vacía y enlace New Course

Con New Course creas un curso con los atributos que declaraste, en este caso solo el título:

Formulario New Course con el campo Title relleno con Curso de Ganchillo y el botón Create Course

Al volver a /courses, el curso nuevo aparece en la lista con sus enlaces para verlo, editarlo o borrarlo:

Lista de cursos con Curso de Ganchillo y los enlaces Show, Edit y Destroy

Las capturas son de Rails 5.2. En Rails 8 el aspecto cambia un poco, pero el flujo es el mismo.

Las rutas: resources :courses

El scaffold añade una línea a config/routes.rb:

resources :courses

Esa línea crea las siete rutas del CRUD (puedes verlas con bin/rails routes -c courses):

Verbo HTTP Ruta Acción Para qué
GET /courses index Listar todos
GET /courses/new new Formulario para crear
POST /courses create Guardar el nuevo
GET /courses/:id show Ver uno
GET /courses/:id/edit edit Formulario para editar
PATCH / PUT /courses/:id update Guardar los cambios
DELETE /courses/:id destroy Borrar
Recorrido de una petición en Rails: GET /courses llega a config/routes.rb, donde resources :courses la lleva a la acción index; CoursesController#index pide al modelo Course todos los cursos con Course.all; y el controlador pinta la vista courses/index.html.erb en el yield del body del layout application.html.erb.
Así recorre Rails una de esas rutas, GET /courses: la ruta elige la acción, el controlador pide los datos al modelo y pinta la vista dentro del layout.

El controlador: recibe la petición

El controlador recibe las peticiones del usuario y habla con el modelo. Cuando pides GET /courses, el servidor lo anota en el log, ejecuta la acción index, hace la consulta de todos los cursos y pinta la vista courses/index.html.erb dentro del layout application:

Started GET "/courses" for 127.0.0.1 at 2018-07-30 08:37:02 +0100
Processing by CoursesController#index as HTML
  Rendering courses/index.html.erb within layouts/application
  Course Load (0.2ms)  SELECT "courses".* FROM "courses"
  ↳ app/views/courses/index.html.erb:14
  Rendered courses/index.html.erb within layouts/application (18.8ms)
Completed 200 OK in 212ms (Views: 207.8ms | ActiveRecord: 1.3ms)

Cada pieza de ese log tiene su fichero en la carpeta app del proyecto:

app/
├── assets/
├── channels/
├── controllers/
│   ├── concerns/
│   ├── application_controller.rb
│   └── courses_controller.rb
├── helpers/
├── jobs/
├── mailers/
├── models/
│   ├── concerns/
│   ├── application_record.rb
│   └── course.rb
└── views/
    ├── courses/
    │   ├── _course.json.jbuilder
    │   ├── _form.html.erb
    │   ├── edit.html.erb
    │   ├── index.html.erb
    │   ├── index.json.jbuilder
    │   ├── new.html.erb
    │   ├── show.html.erb
    │   └── show.json.jbuilder
    └── layouts/
        ├── application.html.erb
        ├── mailer.html.erb
        └── mailer.text.erb

La acción que genera el scaffold es así de corta:

def index
  @courses = Course.all
end

Por defecto, Rails pinta la vista con el mismo nombre que la acción, dentro de la carpeta del controlador, y usa el layout application.html.erb. Si quieres indicar otra plantilla u otro layout, hazlo con render:

def index
  @courses = Course.all
  render template: "courses/index", layout: "application"
end

En el artículo original, con Rails 5.2, la plantilla llevaba la extensión:

# GET /courses
# GET /courses.json
def index
  @courses = Course.all
  render template: "courses/index.html.erb", layout: "application"
end

El modelo: habla con la base de datos

El modelo representa, casi siempre, una tabla de la base de datos y te permite trabajar con ella sin escribir SQL. Course hereda de ApplicationRecord, que a su vez hereda de ActiveRecord::Base, donde están declarados métodos como all, new, save o where.

Los modelos están en app/models:

app/models/
├── concerns/
├── application_record.rb
└── course.rb

course.rb solo declara la herencia:

class Course < ApplicationRecord
end

Y application_record.rb, tal como lo generaba Rails 5.2:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

En Rails 8, application_record.rb usa primary_abstract_class en lugar de self.abstract_class = true; la idea es la misma: es una clase base que no tiene tabla propia.

Puedes probar el modelo directamente en la consola de Ruby on Rails, o hacer el CRUD completo desde ella con CRUD desde consola en Ruby on Rails.

Las vistas: lo que ve el usuario

Las vistas son ficheros HTML con Ruby incrustado (ERB). Están en app/views, normalmente con una carpeta por recurso y una vista por pantalla: listar, ver, crear, editar.

En Rails 5.2, el scaffold de Course generaba estas vistas:

app/views/courses/
├── _course.json.jbuilder
├── _form.html.erb
├── edit.html.erb
├── index.html.erb
├── index.json.jbuilder
├── new.html.erb
├── show.html.erb
└── show.json.jbuilder

En Rails 8 el scaffold genera index, show, new, edit, el formulario compartido _form y el parcial _course. Si tu proyecto incluye la gema jbuilder (viene por defecto con rails new), también genera las vistas .json.jbuilder para responder en JSON.

El layout layouts/application.html.erb tiene la estructura HTML común, y en el body un yield donde Rails incrusta la vista de cada acción:

<!DOCTYPE html>
<html>
  <head>
    <title>MiApp</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>
Ruta, controlador, modelo, vista: cada pieza hace una sola cosa.

Fuentes

Ejecutado con Rails 8.1.4.1 y Ruby 4.0.9 (imagen oficial ruby:latest de Docker): el scaffold de Course y de Coche (que falla), db:migrate, bin/rails routes -c courses y una petición GET /courses con render template con y sin extensión. Las capturas del navegador, los logs y el código de Rails 5.2 son de Rubén.