Blog  34

La maggior parte dei fan di Ruby on Rails sa che Rails 6 è stato rilasciato da poco: ma quali novità e nuove funzionalità porterà con sé?

Lo scopo di questo articolo è quello di familiarizzare con le funzionalità chiave aggiunte a Rails 6 e delineare come possono aiutare a migliorare le nostre applicazioni, risparmiando così tempo prezioso per lo sviluppo, già pregio di questo framework.

Innanzitutto, Rails 6 richiede Ruby 2.5+ e database aggiornati: è necessario, dunque, assicurarsi di aggiornare i propri sistemi nel caso non fosse stato già fatto.

Ma, quali sono queste nuove funzionalità? Ecco un breve riepilogo delle novità chiave di Rails 6 che probabilmente utilizzeremo nell’immediato futuro.

IL TESTING IN RAILS 6

In qualità di sviluppatori Ruby on Rails professionisti, noi di Wonderlab miriamo a garantire la massima sicurezza per il nostro codice. Tuttavia, nei casi di test pesanti e per i quali c’è attesa di minuti o addirittura ore, quest’attività diventa noiosa. Bene: Rails 6 ha una risposta per questo. È stato aggiunto il metodo parallelize alla classe ActiveSupport::TestCase che ci permette di parallelizzare la suite di test attraverso l’utilizzo di processi multipli.

Dunque, per implementare questa novità basta aggiungere la seguente riga al file test_helper.rb:

parallelize(workers: 2)

In alternativa, è possibile sostituire i comandi utilizzati per eseguire i test. Ad esempio, bin/rails test oppure bin/rspec spec possono essere rimpiazzati da PARALLEL_WORKERS=15 rails test oppure PARALLEL_WORKERS=15 rspec spec.

Di conseguenza, è data possibilità di modificare i comandi per eseguire le suite di test su diverse piattaforme CI come Travis, Gitlab, CircleCI e altre ancora.

 

Ad ogni processo creato/distrutto, esistono anche degli hooks, utilizzati come segue:

 

class ActiveSupport::TestCase

parallelize_setup do |worker|

# setup databases

end

 

parallelize_teardown do |worker|

# cleanup databases

end

 

parallelize(workers: :number_of_processors)

end

N.B.: Per approfondire l’argomento e scoprire ulteriori dettagli, è possibile consultare questo link Rails Guides.

TESTING IN ACTION CABLE

Nell’ambito dei test efficienti, è doveroso comprendere anche come Action Cable, una delle caratteristiche più salienti di Rails 5, sia migliorata. Ora è possibile testare Action Cable a qualsiasi livello: connessioni, canali e trasmissioni.

 

I test di connessione hanno lo scopo di verificare se gli identificatori di una connessione vengono assegnati correttamente o se eventuali richieste improprie vengono rifiutate:

 

class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase

test "connects with params" do

 

connect params: { user_id: 42 }

OR

cookies.signed[:user_id] = "42"

connect

 

assert_equal connection.user_id, "42"

end

 

test "rejects connection without params" do

assert_reject_connection { connect }

end

end

 

I test dei canali sono utili per verificare se gli utenti possono iscriversi ai canali; il canale ha uno stream:

 

class ChatChannelTest < ActionCable::Channel::TestCase

test "subscribes and stream for room" do

# Simulate a subscription creation by calling `subscribe`

subscribe room: "15"

 

# You can access the Channel object via `subscription` in tests

assert subscription.confirmed?

assert_has_stream "chat_15"

end

end

Effettuare Broadcasting ai channels può essere testato nel seguente modo:

# app/jobs/chat_relay_job.rb

class ChatRelayJob < ApplicationJob

def perform_later(room, message)

ChatChannel.broadcast_to room, text: message

end

end

 

# test/jobs/chat_relay_job_test.rb

require 'test_helper'

 

class ChatRelayJobTest < ActiveJob::TestCase

include ActionCable::TestHelper

 

test "broadcast message to room" do

room = rooms(:all)

 

assert_broadcast_on(ChatChannel.broadcasting_for(room), text: "Hi!") do

ChatRelayJob.perform_now(room, "Hi!")

end

end

end

N.B: Per maggiori dettagli è possibile consultare questo link Rails Guides.

BULK INSERT E UPSERT

Una delle casistiche usuali nell’operare nell’informatica è la necessità di inserire più record contemporaneamente; attività per la quale ci siamo armati spesso di molte soluzioni alternative.

Bene, Rails 6 fornisce un nuovo metodo “fuori dagli schemi”: insert_all, simile a update_all. Accanto a questi, esiste un metodo aggiuntivo upsert_all che consente di utilizzare l'operazione upsert, esposta da molti database moderni come Postgres. A questo punto, è ora possibile ridurre le query di inserimento e rendere il codice più ottimizzato. Inoltre, possiamo “abbandonare” alcune gemme utilizzate in precedenza come ad esempio activerecord-import. Una singola query INSERT SQL viene preparata con tali metodi e una singola istruzione SQL viene inviata al database, senza creare un'istanza del modello o richiamare callback e convalide di Active Record.

È anche possibile definire criteri in caso di violazione di una chiave primaria (indici univoci o vincoli univoci) con un'opzione per saltare o eseguire query upsert. Di seguito, alcuni esempi:

 

result = Article.insert_all(

[

{ id: 1,

title: 'Titolo Articolo’,

author: 'Mario',

slug: 'titolo-articolo' },

#...snip...

],

returning: %w[ id title ],

unique_by: :index_articles_on_title_and_author

)

 

 

result = Article.upsert_all(

[

{ id: 1, title: 'Titolo Articolo', author: 'Mario', slug: 'titolo-articolo' },

{ id: 1, .... }, # duplicate 'id' here

{ id: 2, .... },

{ id: 3, .... }, # duplicate 'title' and 'author' here

{ id: 4, .... },

{ id: 5, .... }, # duplicate 'slug' here

{ id: 6, .... }

]

)

I metodi insert, insert! e upsert sono rispettivamente dei wrapper di insert_all, insert_all! e upsert_all.

UTILIZZO DI DATABASE MULTIPLI

Una delle funzionalità principali che molte applicazioni di grandi dimensioni apprezzeranno è questa: Rails 6 ha aggiunto il support per utilizzare più database per la stessa applicazione.

 

Ovviamente, la scelta del design rimane allo sviluppatore, sia che voglia suddividere la sua applicazione in più microservizi con ciascuno un database separato, o utilizzare un’architettura monolitica o aggiungere ancora diverse repliche di lettura per la sua applicazione.

 

Tuttavia, avere la capacità di farlo in modo così semplice ha il potenziale per risparmiare molto tempo sul fronte dello sviluppo.

 

Quindi, ecco come apparirà il nuovo file database.yml:

 

development:

primary:

database: my_primary_db

user: root

primary_replica:

database: my_primary_db

user: ro_user

replica: true

animals:

database: my_animals_db

user: root

animals_replica

database: my_animals_db

user: ro_user

replica: true

Di seguito viene mostrato come sia semplice utilizzare i differenti database configurati:

class AnimalsModel < ApplicationRecord

self.abstract_class = true

 

connects_to database: { writing: :animals_primary, reading: :animals_replica }

end

 

class Dog < AnimalsModel

# connesso al db animals_primary in scrittura e a animals_replica in lettura

end

ACTION MAILBOX

Un'altra caratteristica interessante di Rails 6 è l'aggiunta di Action Mailbox, che aggiunge la capacità di instradare le email in arrivo al controller per poterle elaborare, così come avviene con le cassette postali.

Action Mailbox presenta dei connettori per Mailgun, Mandrill, Postmark e SendGrid.

È possibile anche gestire le email in entrata direttamente tramite gli ingressi Exim, Postfix e Qmail.

 

Inoltre, sarebbe possibile elaborare direttamente la posta, automatizzando i ticket di supporto: Rails 6 consente ai clienti di rispondere direttamente tramite e-mail e molto altro ancora.

 

Ecco un piccolo esempio per capire come utilizzare Action Mailbox:

 

COMMENTS_REGEX = /^comment\+(.+)@example\.com/i

 

# app/mailboxes/application_mailbox.rb

class ApplicationMailbox < ActionMailbox::Base

routing COMMENTS_REGEX => :comments

end

 

# app/mailboxes/comments_mailbox.rb

class CommentsMailbox < ApplicationMailbox

def process

user = User.find_by(email: mail.from)

post_uuid = COMMENTS_REGEX.match(mail.to)[1]

 

post = Post.find_by(uuid: post_uuid)

post.comments.create(user: user, content: mail.body)

end

end

 

Il nuovo modo di configurare le email è il seguente (prendendo l'esempio di Sendgrid):

 

# config/environments/production.rb

config.action_mailbox.ingress = :sendgrid

Utilizzare rails credentials:edit per aggiungere la password alle credenziali cifrate della propria applicazione sotto action_mailbox.ingress_password, dove Action Mailbox la ricercherà in automatico:

action_mailbox:

ingress_password: …

Configurare il SendGrid Inbound Parse e inoltrare le email in entrata verso /rails/action_mailbox/sendgrid/inbound_emails con la username actionmailbox e la password precedentemente generata. Se l’applicazione gira sull’indirizzo https://example.com, allora si potrà configurare SendGrid con la seguente URL:

https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/sendgrid/i

ZEITWERK

Zeitwerk è il nuovo caricatore di codice per Ruby. Data una struttura di file convenzionale, Zeitwerk carica le classi e i moduli del progetto su richiesta, il che significa che non è più necessario inserire delle “require” di richiesta per i propri file.

Per abilitarlo in Rails 6:

 

config.autoloader = :zeitwerk

NB: Maggiori dettagli, al seguente link Zeitwerk here.

TRUNCATE DATABASE

La seguente istruzione effettuerà il truncate di tutte le tabelle del proprio database:

rails db:truncate_all

Non dovremo più eliminare l’intero database come si è soliti fare. In molti apprezzeranno questa soluzione veloce ed elegante.

ACTION TEXT

Un'altra caratteristica degna di nota per molte applicazioni che giocano con gli editor WYSIWYG è l'aggiunta del supporto nativo per l'editor Trix nelle applicazioni Rails 6.

 

La maggior parte degli editor HTML WYSIWYG ha una portata enorme: l'implementazione di ogni browser ha il proprio set di bug e stranezze e gli sviluppatori JavaScript devono risolvere le problematiche. Trix elude queste incongruenze trattando il contenuto modificabile come un dispositivo I / O: quando l'input si fa strada nell'editor, Trix converte quell'input in un'operazione di modifica sul suo modello di documento interno, quindi riproduce nuovamente quel documento nell'editor. Questo dà a Trix il controllo completo su ciò che accade dopo ogni pressione di un tasto.

Installazione:

rails action_text:install

 

# app/models/message.rb

class Message < ApplicationRecord

has_rich_text :content

end

SICUREZZA

Nessun aggiornamento serio è completo senza alcuni miglioramenti sulla sicurezza. Rails 6 non delude nemmeno su questo fronte.

Il primo notevole aggiornamento della sicurezza è l'aggiunta del supporto per l'autorizzazione dell'host.

L'autorizzazione host è un nuovo middleware che protegge dagli attacchi di rebinding DNS consentendo esplicitamente agli host di inviare una richiesta. Ciò significa che puoi definire gli host che possono accedere alle applicazioni. Un altro aggiornamento della sicurezza ha lo scopo di contrastare gli attacchi che tentano di copiare il valore firmato / crittografato di un cookie e utilizzarlo come valore di un altro cookie. Lo fa nascondendo il nome del cookie nel campo dello scopo che viene quindi firmato / crittografato insieme al valore dello stesso cookie. Quindi, lato server, verifichiamo i nomi dei cookie e scartiamo quelli attaccati.

È necessario abilitare action_dispatch.use_cookies_with_metadata per utilizzare questa funzione, scrivendo i cookie con il nuovo scopo e i metadati di scadenza incorporati.

DUNQUE CONVIENE AGGIORNARE A RAILS 6?

Rails 6 è certamente un aggiornamento importante da fare, anche se pochi lo definirebbero un punto di svolta.

Dato che Ruby on Rails è in circolazione da anni, poche persone si aspettano cambiamenti rivoluzionari, ma la sua sesta incarnazione sicuramente porta con sé diverse potenzialità.

Alcune funzionalità implementate in Rails 6, infatti, hanno il potenziale per risparmiare molto tempo di sviluppo, migliorare la sicurezza, la robustezza e così via.

In conclusione: Rails è un framework “maturo”, molti sviluppatori rimangono entusiasti del suo futuro e con il rilascio di Rails 6, il tutto è diventato ancora migliore.

Ovviamente, l’elenco delle nuove funzionalità descritte è incompleto e per visualizzare l’intero set di modifiche, è necessario visionare il changelog.

Inoltre, ci sono diverse “deprecations” che vanno prese in considerazione.

Per visualizzare tutti i cambiamenti di questa nuova release, è possibile leggere le note di rilascio.

Articoli Recenti