Skip to content

Instantly share code, notes, and snippets.

@javierav
Created August 17, 2020 07:22
Show Gist options
  • Select an option

  • Save javierav/a61cd6eb8083cbd3f162d1173511e8bb to your computer and use it in GitHub Desktop.

Select an option

Save javierav/a61cd6eb8083cbd3f162d1173511e8bb to your computer and use it in GitHub Desktop.
Introducción a Rails UJS

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.

Instalación

Para poder usar la librería tenemos que añadirla como dependencia a nuestro proyecto.

yarn add @rails/ujs

Asumiendo 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.

Cómo funciona

Acciones

La librería nos permite realizar las siguientes acciones:

  1. Enviar formularios por AJAX (sin recargar la página).
  2. Pedir la página de un enlace por AJAX.
  3. Pedir por AJAX una página al pulsar un botón de un formulario.
  4. Mostrar un mensaje de confirmación antes de realizar una acción.
  5. Desactivar un botón mientras se está enviando el formulario.

Atributos

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:

data-remote

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.

Flujo de ejecución

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

Ejemplos

Enviar un formulario por AJAX y mostrar sus errores

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:

  1. Muestro la página con el formulario.
  2. Cuando el usuario pulsa sobre enviar se envía el formulario a nuestra aplicación Rails.
  3. Si el formulario tiene errores, se vuelve a renderizar la vista del formulario pero mostrando los errores.
  4. 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:

  1. Se recarga la página, por lo que el usuario detecta un pequeño salto.
  2. 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:

  1. El usuario no detecta el salto ya que toda la operación se realiza en segundo plano.
  2. 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.

Controlador

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
end

Resumen

En esta guía hemos visto cómo podemos:

  1. Operaciones que podemos realizar usando la librería de Rails UJS.
  2. Enviar nuestros formularios por AJAX y mostrar sus errores sin necesidad de recargar la página.
  3. Solicitar confirmación de una operación antes de realizar la petición al backend.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment