Bienvenido a la guía sobre el Unobtrusive Javascript que nos proporciona Rails. En esta guía aprenderemos las posibilidades que nos brinda esta librería y cómo podemos usarla en nuestros proyectos para darle dinamismo a nuestra aplicación sin escribir ni una sóla línea de código Javascript.
Para poder usar la librería tenemos que añadirla como dependencia a nuestro proyecto.
yarn add @rails/ujsAsumiendo que en nuestra aplicación Rails estamos usando Webpacker, editaremos el archivo app/javascript/packs/application.js para requerir la dependencia y empezar a usarla.
import railsujs from '@rails/ujs';
railsujs.start();Automáticamente, cada vez que nuestra página se cargue en el navegador, la librería estará pendiente de determinadas acciones sobre elementos HTML concretos y ejecutará el código asociado a la funcionalidad que queremos usar y que veremos en detalle a continuación.
La librería nos permite realizar las siguientes acciones:
- Enviar formularios por AJAX (sin recargar la página).
- Pedir la página de un enlace por AJAX.
- Pedir por AJAX una página al pulsar un botón de un formulario.
- Mostrar un mensaje de confirmación antes de realizar una acción.
- Desactivar un botón mientras se está enviando el formulario.
Toda la lógica de la librería gira en torno al uso de atributos data-* en los elementos HTML, técnica que se conoce como data-behaviour HTML. Los atributos disponibles y su utilidad se describen a continuación:
Se trata del atributo principal de la librería y puede colocarse sobre los elementos HTML form, a, button, select, input y textarea. En función del tipo de elemento reaccionará a un evento del DOM u otro según la siguiente tabla:
| Evento | Elementos |
|---|---|
click |
a y button |
change |
select, input y textarea |
submit |
form |
Si usamos el helper de Rails form_with (que debería ser lo habitual), por defecto y salvo que lo configuremos con la propiedad local: true, ya añade el atributo data-remote="true" al formulario.
Cuando se envía una petición por AJAX y el servidor responde con un estado HTTP válido (2xx), Rails UJS interpreta la respuesta en función del tipo de contenido que sea devuelto:
- Si se trata de contenido Javascript, ejecutará de forma automática ese código. En Rails esta técnica se conoce como Server-generated JavaScript Responses (SJR).
- Ante cualquier otro tipo de contenido no ejecutará ninguna acción por defecto.
En todos los casos Rails UJS lanzará una serie de eventos a los que podremos suscribirnos desde Javascript / Stimulus.js en el elemento que contiene la propiedad data-remote="true" y si nadie detiene la propagación, hasta el objeto document. La lista de eventos es:
| Evento | Cuando se lanza |
|---|---|
| ajax:before | Al comienzo de todo el proceso |
| ajax:beforeSend | Antes de que se envíe la petición |
| ajax:send | Cuando la petición se ha enviado |
| ajax:stopped | Cuando se detiene la petición |
| ajax:success | Al finalizar, si la petición es correcta |
| ajax:error | Al finalizar, si la petición falló |
| ajax:complete | Al finalizar, independientemente del resultado |
Este es quizás el uso más frecuente y a la vez el más potente de los que podemos hacer usando Rails UJS. Antes de usar esta librería, el comportamiento de Rails es:
- Muestro la página con el formulario.
- Cuando el usuario pulsa sobre enviar se envía el formulario a nuestra aplicación Rails.
- Si el formulario tiene errores, se vuelve a renderizar la vista del formulario pero mostrando los errores.
- Si no los tiene, redireccionamos al listado o a la vista show del objeto recién creado.
Aunque esta forma funciona, tiene los siguientes inconvenientes:
- Se recarga la página, por lo que el usuario detecta un pequeño salto.
- Tenemos que volver a renderizar toda la página (layout incluído) si tenemos un error, por lo que el consumo de recursos es mayor (más HTML, más condiciones, más peticiones a la base de datos, etc).
En cambio, si enviamos ese formulario por AJAX y si tiene errores reemplazamos sólo el formulario con la nueva vista que incluye los errores, tendremos como ventajas:
- El usuario no detecta el salto ya que toda la operación se realiza en segundo plano.
- Sólo renderizamos el formulario, por lo que reduciremos la carga del servidor, el número de peticiones a la base de datos, etc.
Para llevar a cabo esto haremos uso del envío remoto de formularios que incorpora la librería y usaremos un pequeño trozo de código Javascript para automatizar la sustitución del HTML de la respuesta.
Nuestro controlador de ejemplo app/controllers/users_controller.rb:
class UsersController < ApplicationController
before_action :find_user, only: %i[edit update]
def new
@user = User.new
authorize @user
end
def edit
end
def create
@user = User.new(permitted_attributes(User))
authorize @user
if @user.save
redirect_to user_path(@user)
else
respond_to do |format|
format.html { render :new, status: 422 }
format.js { render_for_ujs 'form', user: @user }
end
end
end
def update
if @user.update(permitted_attributes(@user))
redirect_to user_path(@user)
else
respond_to do |format|
format.html { render :edit, status: 422 }
format.js { render_for_ujs 'form', user: @user }
end
end
end
private
def find_user
@user = User.find(params[:id])
authorize @user
end
def render_for_ujs(partial, locals={})
render partial: partial, locals: locals, content_type: 'application/html'
end
endEn esta guía hemos visto cómo podemos:
- Operaciones que podemos realizar usando la librería de Rails UJS.
- Enviar nuestros formularios por AJAX y mostrar sus errores sin necesidad de recargar la página.
- Solicitar confirmación de una operación antes de realizar la petición al backend.