Recursos do Rails 6: o que há de novo e por que é importante

Publicados: 2022-03-11

Como a maioria dos fãs de Ruby on Rails deve saber, Rails 6 está chegando em breve, trazendo uma série de recursos e mudanças ansiosamente aguardadas. O objetivo deste artigo é familiarizá-lo com os principais recursos que foram adicionados ao Rails 6 e descrever como eles podem ajudar a melhorar seus aplicativos, economizando tempo valioso de desenvolvimento.

Para começar, lembre-se que Rails 6 requer Ruby 2.5+ e bancos de dados atualizados. Portanto, certifique-se de ter um plano para atualizar seus sistemas de acordo, caso ainda não o tenha feito.

Então, quais são esses novos recursos? Aqui está uma rápida recapitulação dos principais recursos do Rails 6 que você provavelmente usará daqui para frente:

Testando no Rails 6

Como desenvolvedores profissionais de Ruby on Rails, nosso objetivo é garantir a máxima cobertura para nosso código. No entanto, testar se torna uma atividade tediosa quando nossos casos de teste se tornam “pesados” e temos que esperar vários minutos, ou mesmo horas, apenas para que os casos de teste sejam executados.

Testes paralelos

Bem, Rails 6 tem uma resposta aqui. Ele adicionou um método parallelize ao ActiveSupport::TestCase que permite paralelizar o conjunto de testes com processos bifurcados.

Então, o que você precisa fazer para paralelizar os processos para seus testes é adicionar isso ao seu test_helper.rb :

 parallelize(workers: 2)

Alternativamente, podemos substituir nossos comandos usados ​​anteriormente para a execução de testes. Por exemplo, bin/rails test OR bin/rspec spec agora pode ser substituído por PARALLEL_WORKERS=15 rails test OR PARALLEL_WORKERS=15 rspec spec .

Assim, você pode alterar os comandos para executar as suítes de teste em diferentes plataformas de CI, como Travis, Gitlab, CircleCI e outras.

Há também ganchos quando cada processo é criado/destruído, que podem ser usados ​​da seguinte forma:

 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 você quiser saber mais, você pode conferir os Rails Guides para detalhes adicionais.

Teste de cabo de ação

Já que estávamos falando sobre testes eficientes, vamos entender também como o Action Cable, um dos recursos mais importantes do Rails 5, melhorou. Agora é possível testar o Action Cable em qualquer nível: conexões , canais e transmissões .

Os testes de conexão visam verificar se os identificadores de uma conexão são atribuídos corretamente ou se quaisquer solicitações de conexão impróprias são rejeitadas:

 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

Testes de canal podem ser escritos para verificar se os usuários podem se inscrever em canais e se o canal tem um 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

A transmissão para canais pode ser testada assim:

 # 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: Mais dicas sobre como testar podem ser encontradas aqui.

Inserção e Upsert em Massa

Em algum momento, todos nós precisamos inserir vários registros de uma só vez e encontramos muitas soluções alternativas ao fazê-lo. Bem, Rails 6 vem com um novo método pronto para uso— insert_all , similar a update_all .

Ele não acionará nenhum retorno de chamada e executará uma única consulta SQL. Existe um método adicional upsert_all que permite usar a operação upsert que é exposta por muitos bancos de dados modernos como o Postgres. Então agora você pode reduzir suas consultas de inserção e tornar seu código mais otimizado. Além disso, diga adeus às gemas usadas anteriormente, como activerecord-import .

Uma única consulta SQL INSERT é preparada por esses métodos e uma única instrução SQL é enviada ao banco de dados, sem instanciar o modelo ou invocar retornos de chamada e validações do Active Record. Também é possível definir critérios quando uma chave primária — índices exclusivos ou restrições exclusivas são violados com a opção de ignorar ou executar consultas de upsert.

Alguns exemplos estão abaixo:

 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, .... } ] )

Os métodos insert , insert! e upsert são wrappers em torno de insert_all , insert_all! e upsert_all , respectivamente.

Nota: Há um artigo muito bom que discute consultas em massa com relação a diferentes bancos de dados. Se você precisar de informações adicionais, certifique-se de verificar.

Alternando entre vários bancos de dados

Um dos principais recursos que muitos grandes aplicativos apreciarão é este: Rails 6 finalmente adicionou suporte para vários bancos de dados para seu aplicativo, embutido e pronto para uso, pronto para uso!

Diagrama de alternância entre bancos de dados

Obviamente, a escolha do design ainda é sua, quer você queira dividir seu aplicativo em vários microsserviços, cada um com um banco de dados separado, ou seguir uma rota monolítica ou adicionar várias réplicas de leitura para seu aplicativo.

No entanto, ter a capacidade de fazer isso de maneira tão fácil tem o potencial de economizar muito tempo na frente de desenvolvimento.

Então, é assim que seu novo arquivo database.yml ficará:

 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

Aqui estão maneiras interessantes de especificar como alternar para diferentes bancos de dados:

 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

Aqui está a página oficial do GitHub, que também está bem documentada. Pessoalmente, estou ansioso para ter recursos de fragmentação de banco de dados em futuras atualizações do Rails também (algo assim).

Caixa de correio de ação

Outro recurso interessante do Rails 6 é a adição do Action Mailbox, que adiciona a capacidade de rotear e-mails recebidos para o controlador como caixas de correio para processamento no Rails.

A Action Mailbox apresenta entradas para Mailgun, Mandrill, Postmark e SendGrid. Você também pode lidar com e-mails de entrada diretamente por meio de entradas internas do Exim, Postfix e Qmail. Agora, você provavelmente pode imaginar os benefícios potenciais sem entrar em mais detalhes. Ele pode estar processando e-mails diretamente de um help desk para automatizar tíquetes de suporte — o Rails 6 permite que os clientes respondam diretamente por e-mail e muito, muito mais. O chão está aberto para você explorar esse recurso e criar uma abordagem ideal para sua aplicação.

Aqui está um pequeno exemplo para entender como usar o 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

Além disso, a nova maneira de configurar emails é a seguinte (tomando o exemplo do Sendgrid):

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

Use rails credentials:edit para adicionar a senha às credenciais criptografadas do seu aplicativo em action_mailbox.ingress_password , onde o Action Mailbox a encontrará automaticamente:

 action_mailbox: ingress_password: …

Configure o SendGrid Inbound Parse para encaminhar emails de entrada para /rails/action_mailbox/sendgrid/inbound_emails com o nome de usuário actionmailbox e a senha que você gerou anteriormente. Se seu aplicativo estiver em https://example.com , você configuraria o SendGrid com a seguinte URL:

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

Caso você queira explorar isso mais a fundo, o Rails já tem um guia sobre isso aqui.

Zeitwerk

Zeitwerk é o novo carregador de código para Ruby. Dada uma estrutura de arquivo convencional, o Zeitwerk carrega as classes e módulos do seu projeto sob demanda, o que significa que você não precisa escrever chamadas require para seus próprios arquivos. Para habilitá-lo no Rails 6, você pode fazer o seguinte:

 config.autoloader = :zeitwerk

Você pode ler mais sobre Zeitwerk aqui.

Dicas do otimizador

Você está preocupado que algumas de suas consultas estão demorando muito para serem executadas? Bem, agora você também tem uma maneira de definir tempos limite para suas consultas.

A instrução a seguir gerará uma exceção StatementTimeout se a consulta demorar mais do que o normal para ser executada:

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

Ele é suportado pelo MySQL e você terá que explorar se seu banco de dados o suporta.

Truncar banco de dados

E quanto à semeadura de dados? A instrução a seguir truncará todas as suas tabelas de banco de dados e você poderá prosseguir com a propagação de seus dados:

 rails db:truncate_all

Chega de excluir seus bancos de dados para semente. Você provavelmente concordará que esta é uma solução elegante e rápida.

Texto de ação

Talvez outro recurso notável para muitos aplicativos que funcionam com editores WYSIWYG seja a adição de suporte para o editor Trix nativamente em aplicativos Rails 6. Esta será certamente uma boa atualização/adição para muitos projetos.

A maioria dos editores HTML WYSIWYG são enormes em escopo - a implementação de cada navegador tem seu próprio conjunto de bugs e peculiaridades, e os desenvolvedores de JavaScript são deixados para resolver as inconsistências. O Trix evita essas inconsistências tratando o contenteditable como um dispositivo de E/S: Quando a entrada chega ao editor, o Trix converte essa entrada em uma operação de edição em seu modelo de documento interno e, em seguida, renderiza novamente esse documento no editor. Isso dá ao Trix controle completo sobre o que acontece após cada pressionamento de tecla.

Instalação:

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

Você pode explorar o Action Text com mais detalhes na documentação oficial, aqui.

Segurança

Nenhuma atualização séria está completa sem alguns aprimoramentos de segurança. Rails 6 também não decepciona no quesito segurança. A primeira atualização de segurança notável é a adição de suporte para Autorização de Host .

A autorização de host é um novo middleware que protege contra ataques de religação de DNS, permitindo explicitamente aos hosts para os quais uma solicitação pode ser enviada. O que isso significa é que você pode definir os hosts que podem acessar seus aplicativos.

Outra atualização de segurança destina-se a impedir ataques que tentam copiar o valor assinado/criptografado de um cookie e usá-lo como o valor de outro cookie. Ele faz isso armazenando o nome do cookie no campo de finalidade, que é então assinado/criptografado junto com o valor do cookie. Em seguida, na leitura do lado do servidor, verificamos os nomes dos cookies e descartamos quaisquer cookies atacados. Ative action_dispatch.use_cookies_with_metadata para usar esse recurso, que grava cookies com a nova finalidade e metadados de expiração incorporados.

Webpack como o empacotador padrão

Como é o padrão de fato com muitos frameworks JavaScript modernos para desenvolvimento front-end, o Rails 6 adicionou o Webpack como o empacotador JavaScript padrão através do webpacker gem, substituindo o pipeline Rails Asset. Esta é uma adição relativamente simples e não entraremos em muitos detalhes. Basta dizer que o Webpack trará algum alívio aos desenvolvedores front-end sobrecarregados.

Prevenindo Condições de Corrida

Rails 6 tem um novo método que é usado para evitar condições de corrida SELECT/INSERT em nosso código (tenho certeza que muitos leitores tiveram a infelicidade de encontrar condições de corrida enquanto escalam seu projeto). Aqui está o tópico do GitHub caso você precise de informações adicionais.

A tabela subjacente deve ter as colunas relevantes definidas com restrições exclusivas. Enquanto evitamos a condição de corrida entre SELECT → INSERT de #find_or_create_by , na verdade temos outra condição de corrida entre INSERT → SELECT, que pode ser acionada se um DELETE entre essas duas instruções for executado por outro cliente. Mas, para a maioria das aplicações, essa é uma condição que temos muito menos probabilidade de atingir.

Credenciais no Rails 6

Desde os dias do Rails 5.2, as credenciais foram nomeadas como um novo “jeito Rails” para lidar com informações confidenciais com a promessa de se livrar de arquivos .env infames de uma vez por todas. Com credenciais, as chaves criptografadas para serviços de terceiros podem ser verificadas diretamente no controle de origem.

Até agora, no entanto, o Rails usava o mesmo arquivo criptografado para todos os ambientes, o que tornava um pouco complicado lidar com chaves diferentes no desenvolvimento e na produção, especialmente ao lidar com grandes projetos e código legado.

No Rails 6, isso é finalmente resolvido com suporte para credenciais por ambiente. Novamente, mais detalhes podem ser explorados no tópico oficial do GitHub.

Rails 6 é uma boa atualização?

Sim, e de fato o Rails 6 pode ser descrito como uma grande atualização, embora poucos o considerem um divisor de águas. Como o Ruby on Rails existe há anos, poucas pessoas esperam mudanças revolucionárias, mas sua sexta encarnação traz muito para a mesa.

Alguns recursos lançados no Rails 6 parecem pequenas melhorias, enquanto outros têm o potencial de economizar muito tempo de desenvolvimento, melhorar a segurança, robustez e assim por diante. Conclusão: Rails está maduro, muitos desenvolvedores continuam entusiasmados com seu futuro e, com o lançamento do Rails 6, ficou ainda melhor.

Claro, esta lista de recursos do Rails 6 está incompleta e para ver o conjunto completo de mudanças, você precisa conferir o changelog. Além disso, há muitas reprovações que você deve considerar. Por fim, se você insistir em revisar todas as alterações e se atualizar, leia as notas de lançamento completas.