Skip to content

2022_01 Actualización a rails 7

Vladimir Támara Patiño edited this page Jan 15, 2022 · 22 revisions

1. Experimento para transito a rails7

Rails 7 da nuevas posibilidades para integración con Javascript al lado del cliente, sin embargo son muchas opciones mutuamente excluyentes por lo que experimentamos con:

  • Alejarnos de webpacker porque requiere bastantes recursos computacionales y su configuración es compleja
  • Importmaps
  • mrujs como remplazo a @rails/ujs (a futuro sería interesante experimentar con StimulusReflex)
  • Módulos y más ES6
  • Turbo y Stimulus
  • Seguir distribuyendo javascript de motores a aplicaciones mediante sprockets (que nos parece simplifica respecto a publicar paquetes npm --que nos parece ruta interesante cuando tengamos librerías javascript con más utilidad que sólo la requerida por nuestros motores y aplicaciones.
  • Pruebas al sistema con cuprite

2. Conclusiones de los experimentos:

  • Importmaps: es un objetivo a largo plazo interesante, pero requiere bastante esfuerzo en cambios (no soporta coffeescript y la mayoría de motores usan este lenguaje).
  • En lugar de webpacker, encontramos viable el transito y uso de jsbundling-rails con esbuild --posteriormente encontramos esa recomendación en https://noelrappin.com/blog/2021/09/rails-7-and-javascript/
  • mrujs: aunque es interesante y se avanzó por el momento descartamos su uso (ver https://github.com/pasosdeJesus/sivel2_gen/issues/647)
  • Turbo: Nos parece viable pero de manera cauta (mayormente deshabilitado) e ir migrando paulatinamente
  • stimulus: viable incluirlo de manera pre-determinada e ir migrando gradualmente.
  • Módulos y ES6: resultó posible usarlo con sprockets 4, babel-transpiler y emulando minimamente CommonJS, junto con trucos para generar mapas usables por navegador.
  • Continuar usando sprockets es importante para:
    • Migrar paulatinamente. Es decir seguir usando tanto como sea posible lo que se ha legado para el ambiente global de Javascript (incluyendo lo que hay en CoffeeScript y jQuery).
    • Ir organizando lo que vale la pena publicar como módulo y posible futuro paquete npm
  • cuprite: vuelve a hacer viables pruebas al sistema con minitest y capybara.

3. Ruta de acción recomendada

  1. En lo existente pasar a rails7 con las opciones elegidas tras experimentación
  • Cambiar webpacker por jsbundling-rails + esbuild (que es efectivamente rápido y liviano)
  • Agregar gema y paquete turbo-rails y quitar turbolinks pasando eventos y atributos de turbolinks a turbo
  • Agregar gema stimulus-rails
  • Usar gridstack como módulo (y no mediante sprockets)
  • Agregar gema cuprite y al menos una prueba al sistema de ingreso
  1. En lo nuevo que se haga:
  • Evitar jQuery y coffescript
  • En el caso de aplicaciones agregar funcionalidad en app/javascript de una vez como módulo.
  • En el caso de motores agregar nuevas funcionalidad como módulo y con sintaxis y opciones moderna (e.g promesas) en app/javascript/motor_es6.es6 para facilitar futuro paso a app/javascript o empaquetamiento npm
  1. Quitar la dependencia de jQuery que tiene como pre-requisitos cambiar los plugins y las funcionalidades de jQuery:

    • 2.1 Cambiar control de autocompletación que en este momento está con jquery-ui desde sip. No encontramos un remplazo, aunque se ha experimentando con algún éxito con un control implementado desde ceros con el elemento datalist en HTML5.
    • 2.2 Cambiar uso de cocoon que depende de jquery. Para esto se ha empezado a experimentar con stimulus+turbo
    • 2.3 Cambiar uso de chosen en diversos cuadros de selección desde sip. No hemos encontrado un reemplazo equivalente en Javascript puro y chosen no tiene un camino de cambio.
    • 2.4 Cambiar uso de gridstack desde mr519_gen. Encontramos que las versiones recientes posteriores a 1.0.0 no requieren jQuery por lo que se propone actualizar a la versión más reciente.
    • 2.5 Cambiar $.ajax, $.post y demás por fetch --que es más complejo de lo esperado, pudiendo requerir cambios en controladores porque fetch no soporta el método js (que permitía al controlador enviar un javascript que era ejecutado en el cliente), llamando más al envio de HTML.
    • 2.6 En controladores cambiar uso de format.js (que sólo funcionaría con jQuery) con uno de los siguientes:
      • turbo
      • El fetch de mrujs (que en lo investigado hasta ahora requiere cambiar forma de manejar parámetros en controladores) o
      • El envio de formularios que tienen data-remote=true por parte de mrujs.
    • 2.7 Hemos notado que rails7 es más exigente con el token CSRF en las peticiones AJAX, es fácil de agregar como encabezado en peticiones jQuery $.ajax y como parte de los parámetros en $.post. Pero sería mejor usar fetch.
    • 2.8 El envio automático de formularios con remote=true que antes se hacía con @rails/ujs ahora se hace con mrujs que ya no soporta script.
  2. Convertir coffeescript a Javascript

4. Detalle de actualización a rails7 con opciones elegidas tras experimentación

Nos ha resultado útil dividir el transito en dos grandes partes que llamamos al lado del servidor y al lado del cliente.

4.1. Actualización de lo que corre al lado del servidor

  • Emplear rama rails7

  • Gemas: En Gemfile actualizar rails a >~ 7.0 y actualizar gemas dependientes de sip a rama rails7. Cambiar #gem 'byebug' por gem 'debug'. Ejecutar bundle update; bundle

  • Cambiar versión en lib/motor/version.rb

  • Cambiar en fuentes lo que requiere cambios en rails 7 al lado del servidor

    • En bin/gc.sh actualizar db:structure:dump por db:schema:dump
    • En modelos en relaciones belongs_to que no tienen optional agregar optional: false. Ayuda: find . -name "*rb" -exec grep -l "belongs_to" {} ';'
    • Buscar require_dependency y cambiar por require. Ayuda: find . -name "*rb" -exec grep -l "require_dependency" {} ';'
  • Ejecutar bin/rails app:update. Tras esto, si es un motor, en test/dummy/config/boot.rb dejar:

      ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__)
      require "bundler/setup" # Configurar gemas listadas en Gemfile                                  
      require "bootsnap/setup" # Acelerar tiempo de arranque dejando en colchón operaciones costosas                                                   
      $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)  
    
  • En directorio de aplicación config/application.rb cambiar config.load_defaults por 7.0 y agregar g add config/initializers/new_framework_defaults_7_0.rb

  • Verificar que pasan pruebas de regresión con minitest

4.2. Actualización de lo que corre al lado del cliente

  • En Gemfile quitar webpacker y turbolinks y agregar babel-transpiler, jsbundling-rails, sprockets-rails y turbo-rails. Ejecutar bundle update; bundle
  • En directorio de aplicación package.json quitar toda referencia a webpacker, webpack y expose-loader y agregar
"scripts": {
  "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds"
}
  • Correr yarn add esbuild.
  • git rm -rf config/webpack* public/packs
  • mkdir app/assets/builds/; touch app/assets/builds/.mantiene; git add app/assets/builds/.mantiene
  • Agregar app/assets/builds/ a .gitignore
  • Cambiar app/assets/config/manifest.js para que sea al menos el siguiente pero agregar otros que se requieran globalmente y preparados por sprockets:
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
//= link_directory ../../../node_modules/chosen-js .png

//= link application.css
//= link_tree ../builds
  • git mv app/assets/javascripts/application.js app/assets/javascripts/recursos_globales.js
  • git mv app/packs/entrypoints app/javascript
  • Editar app/javascript/application.js para quitar import expose_loader... e import de jquery-ui para reemplazar por:
import './jquery'
import '../../vendedor/recursos/javascripts/jquery-ui'   
  • Crear app/javascript/jquery.js para que sea:
import jquery from 'jquery';                                                     
window.jQuery = jquery;                                                          
window.$ = jquery;     
  • De la distribución de jquery-ui copiar jquery-ui.js en vendedor/recursos/javascripts/jquery-ui.js
  • Ejecutar en modo desarrollo, realizar pruebas de usuarios, asegurar que corren pruebas con sideex
  • Si es el caso ejecutar en modo de ensayo/producción
Clone this wiki locally