Возможности Rails 6: что нового и почему это важно
Опубликовано: 2022-03-11Как известно большинству поклонников Ruby on Rails, скоро выйдет Rails 6, который принесет с собой ряд долгожданных функций и изменений. Цель этой статьи — познакомить вас с ключевыми функциями, которые были добавлены в Rails 6, и показать, как они могут помочь улучшить ваши приложения, тем самым сэкономив драгоценное время разработки.
Для начала помните, что для Rails 6 требуется Ruby 2.5+ и обновленные базы данных. Поэтому убедитесь, что у вас есть план соответствующего обновления ваших систем, если вы еще этого не сделали.
Так что же это за новые функции? Вот краткий обзор ключевых функций Rails 6, которые вы, вероятно, будете использовать в будущем:
Тестирование в Rails 6
Как профессиональные разработчики Ruby on Rails, мы стремимся обеспечить максимальное покрытие нашего кода. Однако тестирование становится утомительным занятием, когда наши тестовые примеры становятся «тяжелыми» и нам приходится ждать несколько минут или даже часов только для того, чтобы их выполнить.
Параллельное тестирование
Что ж, у Rails 6 есть ответ. Он добавил метод parallelize
в ActiveSupport::TestCase
, который позволяет вам распараллелить набор тестов с разветвленными процессами.
Итак, что вам нужно сделать, чтобы распараллелить процессы для ваших тестов, это добавить это в ваш test_helper.rb
:
parallelize(workers: 2)
В качестве альтернативы мы можем заменить наши ранее использовавшиеся команды для запуска тестов. Например, bin/rails test OR bin/rspec spec
теперь можно заменить на PARALLEL_WORKERS=15 rails test OR PARALLEL_WORKERS=15 rspec spec
.
Соответственно, вы можете изменить команды для запуска наборов тестов на разных платформах CI, таких как Travis, Gitlab, CircleCI и других.
Также есть хуки при создании/уничтожении каждого процесса, которые можно использовать следующим образом:
class ActiveSupport::TestCase parallelize_setup do |worker| # setup databases end parallelize_teardown do |worker| # cleanup databases end parallelize(workers: :number_of_processors) end
Примечание. Если вы хотите узнать больше, вы можете обратиться к руководствам по Rails для получения дополнительной информации.
Тестирование кабеля действия
Поскольку мы говорили об эффективном тестировании, давайте также разберемся, как улучшился Action Cable, одна из самых важных функций Rails 5. Теперь можно тестировать Action Cable на любом уровне: подключения , каналы и трансляции .
Тесты подключения направлены на проверку того, правильно ли назначаются идентификаторы подключения или отклоняются ли любые неправильные запросы на подключение:
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
Можно написать тесты каналов , чтобы проверить, могут ли пользователи подписываться на каналы и есть ли на канале поток:
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
Вещание на каналы можно протестировать так:
# 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
Примечание. Дополнительные советы по тестированию можно найти здесь.
Массовая вставка и вставка
В какой-то момент нам всем нужно вставить несколько записей за один раз, и при этом мы нашли множество обходных путей. Итак, Rails 6 поставляется с новым готовым методом — insert_all
, похожим на update_all
.
Он не будет запускать никаких обратных вызовов и выполнит один запрос SQL. Существует дополнительный метод upsert_all
, который позволяет вам использовать операцию upsert, доступную во многих современных базах данных, таких как Postgres. Так что теперь вы можете уменьшить количество запросов на вставку и сделать свой код более оптимизированным. Кроме того, попрощайтесь с ранее использовавшимися драгоценными камнями, такими как activerecord-import
.
Этими методами подготавливается один SQL-запрос INSERT
, и в базу данных отправляется один оператор SQL без создания экземпляра модели или вызова обратных вызовов и проверок Active Record. Также можно определить критерии, когда первичный ключ — уникальные индексы или ограничения уникальности нарушаются, с возможностью либо пропустить, либо запустить запросы upsert.
Некоторые примеры приведены ниже:
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, .... } ] )
Методы insert
, insert!
и upsert
являются обертками вокруг insert_all
, insert_all!
и upsert_all
соответственно.
Примечание. Существует очень хорошая статья, в которой обсуждаются массовые запросы к разным базам данных. Если вам нужна дополнительная информация, обязательно ознакомьтесь с ней.
Переключение между несколькими базами данных
Одной из основных особенностей, которые оценят многие крупные приложения, является следующая: в Rails 6 наконец-то добавлена поддержка нескольких баз данных для вашего приложения, встроенная и готовая к работе прямо из коробки!
Конечно, выбор дизайна по-прежнему остается за вами, хотите ли вы разбить приложение на несколько микросервисов, каждый из которых имеет отдельную базу данных, или выбрать монолитный маршрут, или добавить несколько реплик чтения для вашего приложения.
Однако возможность сделать это таким простым способом может сэкономить много времени на фронте разработки.
Итак, вот как будет выглядеть ваш новый файл 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
Вот интересные способы указать, как переключаться на разные базы данных:
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
Вот официальная страница GitHub, которая также хорошо документирована. Лично я с нетерпением жду возможности сегментирования базы данных в будущих обновлениях Rails (что-то вроде этого).
Почтовый ящик действий
Еще одна интересная функция Rails 6 — это добавление Action Mailbox, который добавляет возможность маршрутизировать входящие электронные письма на контроллер, как почтовые ящики, для обработки в Rails.
В Action Mailbox есть входы для Mailgun, Mandrill, Postmark и SendGrid. Вы также можете обрабатывать входящие электронные письма напрямую через встроенные входы Exim, Postfix и Qmail. Теперь вы, вероятно, можете себе представить потенциальные преимущества, не вдаваясь в подробности. Это может быть прямая обработка писем из службы поддержки или автоматизация заявок в службу поддержки — Rails 6 позволяет клиентам отвечать напрямую по электронной почте и многое, многое другое. Вы можете изучить эту функцию и найти подход, идеально подходящий для вашего приложения.

Вот небольшой пример, чтобы понять, как использовать почтовый ящик действий:
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
Кроме того, новый способ настройки электронной почты выглядит следующим образом (на примере Sendgrid):
# config/environments/production.rb config.action_mailbox.ingress = :sendgrid
Используйте rails credentials:edit
, чтобы добавить пароль к зашифрованным учетным данным вашего приложения в action_mailbox.ingress_password
, где Action Mailbox автоматически найдет его:
action_mailbox: ingress_password: …
Настройте синтаксический анализ входящих сообщений SendGrid для пересылки входящих сообщений электронной почты на /rails/action_mailbox/sendgrid/inbound_emails
с именем пользователя actionmailbox
и сгенерированным ранее паролем. Если ваше приложение находится по адресу https://example.com
, вы должны настроить SendGrid со следующим URL-адресом:
https://actionmailbox:[email protected]/rails/action_mailbox/sendgrid/i
Если вы хотите изучить это подробнее, у Rails уже есть руководство по этому вопросу здесь.
Цайтверк
Zeitwerk — новый загрузчик кода для Ruby. Учитывая обычную файловую структуру, Zeitwerk загружает классы и модули вашего проекта по запросу, что означает, что вам не нужно писать вызовы require для ваших собственных файлов. Чтобы включить его в Rails 6, вы можете сделать следующее:
config.autoloader = :zeitwerk
Подробнее о Zeitwerk можно прочитать здесь.
Подсказки оптимизатора
Вы обеспокоены тем, что некоторые из ваших запросов выполняются слишком долго? Ну, теперь у вас есть способ определить тайм-ауты и для ваших запросов.
Следующий оператор вызовет исключение StatementTimeout
, если выполнение запроса занимает больше времени, чем обычно:
User.optimizer_hints("MAX_EXECUTION_TIME(5000)").all
Он поддерживается MySQL, и вам придется выяснить, поддерживает ли его ваша база данных.
Усечение базы данных
А как насчет начальных данных? Следующий оператор усекает все ваши таблицы базы данных, после чего вы можете перейти к заполнению ваших данных:
rails db:truncate_all
Больше не нужно удалять базы данных для раздачи. Вы, вероятно, согласитесь, что это элегантное и быстрое решение.
Текст действия
Возможно, еще одной примечательной особенностью многих приложений, работающих с WYSIWYG-редакторами, является добавление встроенной поддержки редактора Trix в приложения Rails 6. Это, безусловно, будет хорошим обновлением/дополнением для многих проектов.
Большинство HTML-редакторов WYSIWYG имеют огромные возможности — реализация каждого браузера имеет свой собственный набор ошибок и особенностей, и разработчикам JavaScript приходится устранять несоответствия. Trix обходит эти несоответствия, рассматривая contenteditable
как устройство ввода-вывода: когда ввод поступает в редактор, Trix преобразует этот ввод в операцию редактирования своей внутренней модели документа, а затем повторно отображает этот документ обратно в редактор. Это дает Трикс полный контроль над тем, что происходит после каждого нажатия клавиши.
Установка:
rails action_text:install # app/models/message.rb class Message < ApplicationRecord has_rich_text :content end
Вы можете более подробно изучить Action Text в официальной документации здесь.
Безопасность
Ни одно серьезное обновление не обходится без нескольких улучшений безопасности. Rails 6 также не разочаровывает в плане безопасности. Первым заметным обновлением безопасности является добавление поддержки авторизации хоста .
Авторизация хоста — это новое промежуточное программное обеспечение, которое защищает от атак повторной привязки DNS, явно разрешая хосты, на которые может быть отправлен запрос. Это означает, что вы можете определить хосты, которые могут получить доступ к вашим приложениям.
Еще одно обновление безопасности предназначено для предотвращения атак, которые пытаются скопировать подписанное/зашифрованное значение файла cookie и использовать его в качестве значения другого файла cookie. Он делает это, сохраняя имя файла cookie в поле назначения, которое затем подписывается/зашифровывается вместе со значением файла cookie. Затем при чтении на стороне сервера мы проверяем имена файлов cookie и отбрасываем все атакованные файлы cookie. Включите action_dispatch.use_cookies_with_metadata
, чтобы использовать эту функцию, которая записывает файлы cookie со встроенными метаданными нового назначения и срока действия.
Webpack как упаковщик по умолчанию
Поскольку де-факто является стандартом для многих современных JavaScript-фреймворков для фронтенд-разработки, в Rails 6 добавлен Webpack в качестве сборщика JavaScript по умолчанию через гем webpacker, заменяющий конвейер ресурсов Rails. Это относительно простое дополнение, и мы не будем вдаваться в подробности. Достаточно сказать, что Webpack принесет некоторое облегчение переутомленным фронтенд-разработчикам.
Предотвращение состояний гонки
В Rails 6 есть новый метод, который используется для предотвращения условий гонки SELECT/INSERT в нашем коде (я уверен, что многие читатели имели несчастье столкнуться с условиями гонки при масштабировании своего проекта). Вот поток GitHub, если вам нужна дополнительная информация.
Базовая таблица должна иметь соответствующие столбцы, определенные с уникальными ограничениями. Хотя мы избегаем состояния гонки между SELECT → INSERT из #find_or_create_by
, у нас фактически есть другое состояние гонки между INSERT → SELECT, которое может быть вызвано, если DELETE между этими двумя операторами выполняется другим клиентом. Но для большинства приложений это условие, с которым мы сталкиваемся значительно реже.
Учетные данные в Rails 6
Со времен Rails 5.2 учетные данные были названы новым «способом Rails» для работы с конфиденциальной информацией с обещанием раз и навсегда избавиться от печально известных файлов .env . С помощью учетных данных зашифрованные ключи для сторонних служб можно проверить непосредственно в системе управления версиями.
Однако до сих пор Rails использовал один и тот же зашифрованный файл для всех сред, что усложняло работу с разными ключами при разработке и производстве, особенно при работе с большими проектами и унаследованным кодом.
В Rails 6 эта проблема, наконец, решена благодаря поддержке учетных данных для каждой среды. Опять же, дополнительные подробности можно изучить в официальной ветке GitHub.
Является ли Rails 6 хорошим обновлением?
Да, и на самом деле Rails 6 можно назвать крупным обновлением, хотя мало кто назовет его революционным. Поскольку Ruby on Rails существует уже много лет, мало кто ожидает революционных изменений, но его шестое воплощение приносит многое.
Некоторые функции, реализованные в Rails 6, кажутся незначительными улучшениями, в то время как другие могут сэкономить много времени на разработку, повысить безопасность, надежность и т. д. Итог: Rails созрел, многие разработчики с энтузиазмом смотрят на его будущее, а с выпуском Rails 6 он стал еще лучше.
Конечно, этот список функций Rails 6 неполный, и для просмотра полного набора изменений вам необходимо просмотреть список изменений. Кроме того, есть много недостатков, которые вы должны учитывать. Наконец, если вы настаиваете на том, чтобы просмотреть каждое отдельное изменение и обновить его самостоятельно, прочтите полные примечания к выпуску.