Caratteristiche di Rails 6: cosa c'è di nuovo e perché è importante

Pubblicato: 2022-03-11

Come la maggior parte dei fan di Ruby on Rails potrebbe sapere, Rails 6 arriverà presto e porterà una serie di funzionalità e modifiche tanto attese. Lo scopo di questo articolo è familiarizzare con le funzionalità chiave che sono state aggiunte a Rails 6 e delineare come possono aiutare a migliorare le tue applicazioni, risparmiando così tempo prezioso di sviluppo.

Per cominciare, ricorda che Rails 6 richiede Ruby 2.5+ e database aggiornati. Quindi, assicurati di avere un piano per aggiornare i tuoi sistemi di conseguenza, nel caso non lo avessi già fatto.

Quindi quali sono queste nuove funzionalità? Ecco un breve riepilogo delle principali funzionalità di Rails 6 che probabilmente utilizzerai in futuro:

Test su Rails 6

In qualità di sviluppatori professionisti di Ruby on Rails, miriamo a garantire la massima copertura per il nostro codice. Tuttavia, il test diventa un'attività noiosa quando i nostri test case diventano "pesanti" e dobbiamo aspettare diversi minuti, o addirittura ore, solo per eseguire i test case.

Prove parallele

Bene, Rails 6 ha una risposta qui. Ha aggiunto un metodo parallelize ad ActiveSupport::TestCase che consente di parallelizzare la suite di test con processi biforcati.

Quindi, quello che devi fare per parallelizzare i processi per i tuoi test è aggiungere questo al tuo test_helper.rb :

 parallelize(workers: 2)

In alternativa, possiamo sostituire i nostri comandi utilizzati in precedenza per l'esecuzione dei test. Ad esempio, bin/rails test OR bin/rspec spec ora può essere sostituito da PARALLEL_WORKERS=15 rails test OR PARALLEL_WORKERS=15 rspec spec .

Di conseguenza, puoi modificare i comandi per eseguire le suite di test su diverse piattaforme CI come Travis, Gitlab, CircleCI e altre.

Ci sono anche hook quando ogni processo viene creato/distrutto, che possono essere 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

Nota: se desideri saperne di più, puoi consultare Rails Guides per ulteriori dettagli.

Azione Test dei cavi

Visto che si parlava di test efficienti, capiamo anche come sia migliorato Action Cable, una delle caratteristiche più salienti di Rails 5. Ora è possibile testare Action Cable a qualsiasi livello: connessioni , canali e trasmissioni .

I test di connessione mirano a verificare se gli identificatori di una connessione vengono assegnati correttamente o se le richieste di connessione 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 possono essere scritti per verificare se gli utenti possono iscriversi ai canali e se 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

La trasmissione ai canali può essere testata in questo 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

Nota: qui puoi trovare ulteriori suggerimenti su come eseguire il test.

Inserimento e inserimento in blocco

Ad un certo punto, tutti abbiamo bisogno di inserire più record in una volta sola e abbiamo trovato molte soluzioni alternative durante l'operazione. Bene, Rails 6 viene fornito con un nuovo metodo pronto all'uso: insert_all , simile a update_all .

Non attiverà alcun callback ed eseguirà una singola query SQL. Esiste un metodo aggiuntivo upsert_all che consente di utilizzare l'operazione upsert esposta da molti database moderni come Postgres. Quindi ora puoi ridurre le tue query di inserimento e rendere il tuo codice più ottimizzato. Inoltre, saluta le gemme utilizzate in precedenza come activerecord-import .

Con questi metodi viene preparata una singola query INSERT SQL e una singola istruzione SQL viene inviata al database, senza creare un'istanza del modello o invocare callback e convalide di Active Record. È anche possibile definire criteri quando una chiave primaria, indici univoci o vincoli univoci, viene violata con un'opzione per saltare o eseguire query di upsert.

Alcuni esempi sono di seguito:

 result = Article.insert_all( [ { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' }, #...snip... ], returning: %w[ id title ], unique_by: :index_articles_on_title_and_author ) result = Article.upsert_all( [ { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' }, { 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 wrapper intorno a insert_all , insert_all! e upsert_all , rispettivamente.

Nota: c'è un ottimo articolo che discute le query in blocco rispetto a database diversi. Se hai bisogno di ulteriori informazioni, assicurati di controllarle.

Passaggio tra più database

Una delle caratteristiche principali che molte grandi applicazioni apprezzeranno è questa: Rails 6 ha finalmente aggiunto il supporto per più database per la tua applicazione, integrato e pronto per l'uso, fuori dagli schemi!

Diagramma di passaggio tra database

Naturalmente, la scelta del design è ancora tua, sia che tu voglia suddividere la tua applicazione in più microservizi con ciascuno dotato di un database separato, o intraprendere un percorso monolitico o aggiungere diverse repliche di lettura per la tua applicazione.

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

Quindi, ecco come apparirà il tuo 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

Ecco alcuni modi interessanti per specificare come passare a database diversi:

 class AnimalsModel < ApplicationRecord self.abstract_class = true connects_to database: { writing: :animals_primary, reading: :animals_replica } end class Dog < AnimalsModel # connected to both the animals_primary db for writing and the animals_replica for reading end

Ecco la pagina ufficiale di GitHub, anch'essa ben documentata. Personalmente, non vedo l'ora di avere capacità di sharding del database anche nei futuri aggiornamenti di Rails (qualcosa del genere).

Cassetta postale di azione

Un'altra caratteristica interessante di Rails 6 è l'aggiunta di Action Mailbox, che aggiunge la capacità di instradare le e-mail in arrivo al controller come le cassette postali per l'elaborazione in Rails.

Action Mailbox include ingressi per Mailgun, Mandrill, Postmark e SendGrid. Puoi anche gestire le email in entrata direttamente tramite gli ingressi Exim, Postfix e Qmail integrati. Ora, puoi probabilmente immaginare i potenziali benefici senza entrare più nel dettaglio. Potrebbe elaborare direttamente la posta da un help desk all'automazione dei ticket di supporto: Rails 6 consente ai clienti di rispondere direttamente tramite e-mail e molto altro ancora. Il pavimento è aperto per esplorare questa funzionalità e trovare un approccio ideale per la tua applicazione.

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

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

 # config/environments/production.rb config.action_mailbox.ingress = :sendgrid

Usa rails credentials:edit per aggiungere la password alle credenziali crittografate della tua applicazione in action_mailbox.ingress_password , dove Action Mailbox la troverà automaticamente:

 action_mailbox: ingress_password: …

Configura SendGrid Inbound Parse per inoltrare le email in entrata a /rails/action_mailbox/sendgrid/inbound_emails con il nome utente actionmailbox e la password che hai generato in precedenza. Se la tua applicazione risiede su https://example.com , configureresti SendGrid con il seguente URL:

 https://actionmailbox:[email protected]/rails/action_mailbox/sendgrid/i

Nel caso in cui desideri approfondire ulteriormente, Rails ha già una guida su questo qui.

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 è necessario scrivere richieste di chiamate per i propri file. Per abilitarlo in Rails 6, puoi fare quanto segue:

 config.autoloader = :zeitwerk

Puoi leggere di più su Zeitwerk qui.

Suggerimenti per l'ottimizzatore

Sei preoccupato che alcune delle tue query richiedano troppo tempo per essere eseguite? Bene, ora hai anche un modo per definire i timeout per le tue query.

La seguente istruzione genererà un'eccezione StatementTimeout se la query impiega più tempo del normale per essere eseguita:

 User.optimizer_hints("MAX_EXECUTION_TIME(5000)").all

È supportato da MySQL e dovrai esplorare se il tuo database lo supporta.

Tronca database

E per quanto riguarda il seeding dei dati? La seguente istruzione troncherà tutte le tabelle del database e potrai quindi procedere al seeding dei tuoi dati:

 rails db:truncate_all

Non dovrai più eliminare i tuoi database per eseguire il seeding. Probabilmente sarai d'accordo che questa è una soluzione elegante e veloce.

Testo d'azione

Forse un'altra caratteristica degna di nota per molte applicazioni che giocano con gli editor WYSIWYG è l'aggiunta del supporto per l'editor Trix in modo nativo nelle applicazioni Rails 6. Questo sarà sicuramente un buon aggiornamento/aggiunta per molti progetti.

La maggior parte degli editor HTML WYSIWYG ha una portata enorme: l'implementazione di ogni browser ha la propria serie di bug e stranezze e gli sviluppatori JavaScript devono risolvere le incongruenze. Trix elude queste incongruenze trattando il contenteditable modificabile come un dispositivo I/O: quando l'input arriva all'editor, Trix converte quell'input in un'operazione di modifica sul suo modello di documento interno, quindi esegue nuovamente il rendering del documento nell'editor. Questo dà a Trix il controllo completo su ciò che accade dopo ogni battitura.

Installazione:

 rails action_text:install # app/models/message.rb class Message < ApplicationRecord has_rich_text :content end

Puoi esplorare il testo dell'azione in modo più dettagliato nella documentazione ufficiale, qui.

Sicurezza

Nessun aggiornamento serio è completo senza alcuni miglioramenti della sicurezza. Rails 6 non delude nemmeno sul fronte della sicurezza. Il primo notevole aggiornamento della sicurezza è l'aggiunta del supporto per l'autorizzazione dell'host .

L'autorizzazione dell'host è un nuovo middleware che protegge dagli attacchi di riassociazione DNS consentendo esplicitamente agli host a cui è possibile inviare una richiesta. Ciò significa che puoi definire gli host che possono accedere alle tue 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 di utilizzarlo come valore di un altro cookie. Lo fa riponendo il nome del cookie nel campo dello scopo che viene quindi firmato/crittografato insieme al valore del cookie. Quindi, nella lettura lato server, verifichiamo i nomi dei cookie e scartiamo tutti i cookie attaccati. Abilita action_dispatch.use_cookies_with_metadata per utilizzare questa funzione, che scrive i cookie con il nuovo scopo e i metadati di scadenza incorporati.

Webpack come bundler predefinito

Come è lo standard de facto con molti framework JavaScript moderni per lo sviluppo front-end, Rails 6 ha aggiunto Webpack come bundler JavaScript predefinito tramite webpacker gem, sostituendo la pipeline Rails Asset. Questa è un'aggiunta relativamente semplice e non entreremo nei dettagli. Basti dire che Webpack porterà un po' di sollievo agli sviluppatori front-end oberati di lavoro.

Prevenire le condizioni di gara

Rails 6 ha un nuovo metodo che viene utilizzato per prevenire condizioni di gara SELECT/INSERT nel nostro codice (sono sicuro che molti lettori hanno avuto la sfortuna di incontrare condizioni di gara mentre ridimensionano il loro progetto). Ecco il thread di GitHub nel caso abbiate bisogno di ulteriori informazioni.

La tabella sottostante deve avere le colonne pertinenti definite con vincoli univoci. Mentre evitiamo la race condition tra SELECT → INSERT da #find_or_create_by , in realtà abbiamo un'altra race condition tra INSERT → SELECT, che può essere attivata se un DELETE tra queste due istruzioni viene eseguito da un altro client. Ma, per la maggior parte delle applicazioni, questa è una condizione che è molto meno probabile che si verifichi.

Credenziali in Rails 6

Dai tempi di Rails 5.2, le credenziali sono state chiamate un nuovo "modo Rails" per gestire le informazioni sensibili con la promessa di sbarazzarsi dei famigerati file .env una volta per tutte. Con le credenziali, le chiavi crittografate per servizi di terze parti possono essere archiviate direttamente nel controllo del codice sorgente.

Finora, tuttavia, Rails utilizzava lo stesso file crittografato per tutti gli ambienti, il che rendeva un po' complicato gestire chiavi diverse in fase di sviluppo e produzione, soprattutto quando si trattava di grandi progetti e codice legacy.

In Rails 6, questo è finalmente risolto con il supporto per le credenziali per ambiente. Ancora una volta, ulteriori dettagli possono essere esplorati sul thread ufficiale di GitHub.

Rails 6 è un buon aggiornamento?

Sì, e in effetti Rails 6 potrebbe essere descritto come un aggiornamento importante, anche se pochi lo chiamerebbero un punto di svolta. Dato che Ruby on Rails è in circolazione da anni, poche persone si aspettano cambiamenti rivoluzionari, ma la sua sesta incarnazione porta molto sul tavolo.

Alcune funzionalità implementate in Rails 6 sembrano piccoli miglioramenti, mentre altre hanno il potenziale per risparmiare molto tempo di sviluppo, migliorare la sicurezza, la robustezza e così via. In conclusione: Rails è maturo, molti sviluppatori rimangono entusiasti del suo futuro e, con il rilascio di Rails 6, è migliorato ancora.

Naturalmente, questo elenco di funzionalità di Rails 6 è incompleto e per visualizzare l'insieme completo delle modifiche, è necessario controllare il log delle modifiche. Inoltre, ci sono molte deprecazioni che dovresti considerare. Infine, se insisti nell'esaminare ogni singola modifica e aggiornarti, leggi le note di rilascio complete.