Entendiendo un controlador en Ruby on Rails

Por Andrés Howard | June 23

Los controladores son una parte esencial de una aplicación de Ruby on Rails, sin ir más allá el patrón base del framework es MVC (Modelo, Vista Controlador). El controlador es el encargado de hacerse cargo de la solicitud que recibe la aplicación de parte del user-agent (el usuario). Para eso se apoya del Modelo y de las Vistas.

Veamos un controlador de ejemplo con las 7 acciones comunes necesarias para soportar CRUD de un recurso. Para términos del ejemplo vamos a hacer el controlador de libros, que permite crear, ver, actualizar y eliminar (CRUD) libros.

1. Dónde está el controlador?

Partamos por la ubicación y la estructura

# app/controllers/books_controller.rb
class BooksController < ApplicationController
end

Los controladores se encuentran en la carpeta app/controllers y llevan el nombre del recurso en plural. Podemos apreciar que el controlador hereda de la clase ApplicationController, esto nos permite compartir comportamientos entre todos los controladores de la aplicación mediante herencia.

2. Acciones para crear un nuevo elemento

Para crear elementos (en este caso libros) nuevos, el controlador necesita 2 acciones (métodos):

# app/controllers/books_controller.rb
class BooksController < ApplicationController
  def new
    @book = Book.new
  end

  def create
    book = Book.new book_params
    if book.save
      redirect_to book
    else
      render :new
    end
  end

  private

  def book_params
    params.require(:book).permit(:title, :author)
  end
end

Podemos ver que tenemos dos acciones principales new y create. La primera se encarga de crear un libro en memoria con todos sus campos vacíos para que la vista cree un formulario que permita al usuario completar esos campos. Por otro lado, cuando el usuario completa el formulario y presionar enviar esos datos son recibidos por la acción create, que se encarga de instanciar el libro en memoria y luego mediante book.save trata de almacenarlo en la base de datos. Dicha función retorna true si logró guardar el libro y false en caso contrario, con eso podemos tomar la decisión de qué hacer en cada caso. La convención más tradicional es mostrar nuevamente el formulario junto con el detalle de los errores que hubo si no logró almacenarse, y si fue exitoso llevar al usuario a la vista del libro.

3. Acciones para mostrar elementos existentes

Para mostrar los elementos existentes tenemos 2 acciones

# app/controllers/books_controller.rb
class BooksController < ApplicationController
  def index
    @books = Book.all
  end

  def show
    @book = Book.find params[:id]
  end
end

La primera acción, index, lo que hace es cargar todos los libros que tenemos en la base de datos (suele cambiarse eso por todos los que tenga permiso el usuario para ver) y la acción show nos permite ver un libro en particular en base al id del libro que viene en la url a la que estamos accediendo (y que obtenemos en la variable params[:id])

4. Acciones para actualizar un elemento

Para actualizar un elemento existente necesitamos 2 acciones (al igual que para la creación): uno para mostrar el formulario al usuario con los datos actuales del elemento, y otra para ejecutar la actualización en la base de datos del elemento con los datos enviados por el usuario en el formulario.


# app/controllers/books_controller.rb
class BooksController < ApplicationController
  def edit
    @book = Book.find params[:id]
  end

  def update
    book = Book.new book_params
    if book.update
      redirect_to book
    else
      render :edit
    end
  end

  private

  def book_params
    params.require(:book).permit(:title, :author)
  end
end
La lógica de ambas acciones es exactamente la misma que en la creación. La única diferencia es que en el update, en lugar de ejecutar un save ejecuta update, pero el resultado es el mismo: retorna true o false dependiendo si logra almacenar los cambios en la base de datos.

5. Acción para eliminar un elemento

La última de las acciones para obtener el CRUD completo es la eliminación. Para esto en el controlador tenemos la siguiente acción:

# app/controllers/books_controller.rb
class BooksController < ApplicationController
  def destroy
    book = Book.find params[:id]
    book.destroy
    redirect_to books_path
  end
end
Esta acción lo que hace es buscar el libro en base al id que recibe en la url a través de la variable params y luego lo elimina, para finalmente llevar al usuario al index de libros (donde ya no debería aparecer el libro eliminado).

El controlador que vimos aquí es uno básico en base a las convenciones de Ruby on Rails, obviamente puede ser modificado mucho en base a los distintos casos de uso que tengamos.

A continuación dejo el código completo del controlador:

# app/controllers/books_controller.rb
class BooksController < ApplicationController
  def index
    @books = Book.all
  end

  def new
    @book = Book.new
  end

  def show
    @book = Book.find params[:id]
  end

  def edit
    @book = Book.find params[:id]
  end

  def update
    book = Book.find params[:id]
    if book.update
      redirect_to book
    else
      render :edit
    end
  end

  def create
    book = Book.new books_params
    if book.save
      redirect_to book
    else
      render :new
    end
  end

  def destroy
    book = Book.find params[:id]
    book.destroy
    redirect_to books_path
  end

  private

    def books_params
      params.require(:book).permit(:title, ...)
    end
end