Заметки о релизе Ruby on Rails 5.2

Ключевые новинки в Rails 5.2:

  • Active Storage
  • Хранилище кэша Redis
  • HTTP/2 Early Hints
  • Учетные данные (Credentials)
  • Политика безопасности контента (CSP)

Эти заметки о релизе покрывают только основные изменения. Чтобы узнать о других обновлениях, различных исправлениях программных ошибок и изменениях, обратитесь к логам изменений или к списку коммитов в главном репозитории Rails на GitHub.


1. Апгрейд до Rails 5.2

Прежде чем апгрейднуть существующее приложение, было бы хорошо иметь перед этим покрытие тестами. Также, до попытки обновиться до Rails 5.2, необходимо сначала произвести апгрейд до Rails 5.1 и убедиться, что приложение все еще выполняется так, как нужно. Список вещей, которые нужно выполнить для апгрейда доступен в руководстве Апгрейд Ruby on Rails.

2. Основные особенности

2.1. Active Storage

Pull Request

Active Storage облегчает загрузку файлов в облачные хранилища данных, такие как Amazon S3, Google Cloud Storage или Microsoft Azure Storage, и прикрепляет эти файлы к объектам Active Record. Он поставляется с локальным на основе диска сервисом для разработки и тестирования, и поддерживает отзеркаливание (mirroring) файлов в подчиненных сервисах для резервного копирования и миграций. Подробнее об Active Storage можно прочитать в руководстве Обзор Active Storage.

2.2. Хранилище кэша Redis

Pull Request

Rails 5.2 поставляется со встроенным хранилищем кэша Redis. Подробнее об этом можно прочитать в руководстве Кэширование с Rails: Обзор.

2.3. HTTP/2 Early Hints

Pull Request

Rails 5.2 поддерживает HTTP/2 Early Hints. Чтобы запустить сервер с включенными Early Hints, необходимо передать --early-hints вместе с bin/rails server.

2.4. Учетные данные

Pull Request

Добавлен файл config/credentials.yml.enc для хранения секретов приложения в production. Это разрешает сохранять любые учетные данные аутентификации для сторонних сервисов напрямую в репозиторий, зашифрованный с помощью ключа в файле config/master.key или переменной среды RAILS_MASTER_KEY. Это в конечном итоге заменит Rails.application.secrets и зашифрованные секреты, представленные в Rails 5.1. Кроме того, Rails 5.2 открывает API соответствующие учетным данным, поэтому можно легко справиться с другими зашифрованными конфигурациями, ключами и файлами.

Подробнее об этом можно узнать в руководстве Безопасность приложений на Rails.

2.5. Политика безопасности контента

Pull Request

Rails 5.2 поставляется с новым DSL, который разрешает конфигурировать политику безопасности контента для приложения. Также можно сконфигурировать глобальную дефолтную политику, а затем переопределить ее отдельно для каждого ресурса и даже использовать лямбды для ввода значений для каждого запроса в заголовок, такой как поддомены аккаунта в многопользовательском (multi-tenant) приложении.

Подробнее об этом можно узнать в руководстве руководстве Безопасность приложений на Rails.

3. Railties

За подробностями обратитесь к Changelog.

3.1. Устарело

  • Устарел метод capify! в генераторах и шаблонах. (Pull Request)

  • Передача имени среды в качестве обычного аргумента устарела для команд rails dbconsole и rails console. Вместо этого следует использовать опцию -e. (Commit)

  • Устарело использование подкласса Rails::Application для запуска сервера Rails. (Pull Request)

  • Устарел колбэк after_bundle в шаблонах плагина Rails. (Pull Request)

3.2. Значимые изменения

  • Добавлен общий раздел config/database.yml, который будет загружен для всех сред. (Pull Request)

  • Добавлен railtie.rb в генератор плагина. (Pull Request)

  • Очистка скриншотов в задаче tmp:clear. (Pull Request)

  • Пропуск неиспользуемых компонентов при запуске bin/rails app:update. Если начальная генерация приложения пропустила Action Cable, Active Record и т.д., задача update учтет эти пропуски тоже. (Pull Request)

  • Разрешает передачу имени собственного соединения в команду rails dbconsole при использовании 3-уровневой конфигурации базы данных. Пример: bin/rails dbconsole -c replica. (Commit)

  • Правильно расширены краткие формы для имени среды, запускающие команды console и dbconsole. (Commit)

  • Добавлен bootsnap в Gemfile по умолчанию. (Pull Request)

  • Поддержка - как платформо-агностического способа для запуска скрипта из stdin с помощью rails runner (Pull Request)

  • Добавлена версия ruby x.x.x в Gemfile и создан корневой файл .ruby-version, содержащий текущую версию Ruby при создании нового приложения Rails. (Pull Request)

  • Добавлена опция --skip-action-cable в генератор плагина. (Pull Request)

  • Добавлен git_source в Gemfile для генератора плагина. (Pull Request)

  • Пропуск неиспользуемых компонентов при запуске bin/rails в плагинах Rails. (Commit)

  • Оптимизированы отступы для экшнов генератора. (Pull Request)

  • Оптимизированы отступы маршрутов. (Pull Request)

  • Добавлена опция --skip-yarn в генератор плагина. (Pull Request)

  • Поддержка нескольких версий аргументов для метода gem в Generators. (Pull Request)

  • Вынесен secret_key_base из имени приложения в средах разработки и тестирования. (Pull Request)

  • Добавлен mini_magick как комментарий в дефолтный Gemfile. (Pull Request)

  • rails new и rails plugin new получают Active Storage по умолчанию. Добавлена возможность пропускать Active Storage с помощью --skip-active-storage и делать это автоматически, если используется --skip-active-record. (Pull Request)

4. Action Cable

За подробностями обратитесь к Changelog.

4.1. Удалено

  • Удален устаревший событийный адаптер redis. (Commit)

4.2. Значимые изменения

  • Добавлена поддержка для опций host, port, db и password в cable.yml (Pull Request)

  • Длинные идентификаторы потока хэша при использовании адаптера PostgreSQL. (Pull Request)

5. Action Pack

За подробностями обратитесь к Changelog.

5.1. Удалено

  • Удален устаревший ActionController::ParamsParser::ParseError. (Commit)

5.2. Устарело

  • Устарели псевдонимы #success?, #missing? и #error? для ActionDispatch::TestResponse. (Pull Request)

5.3. Значимые изменения

  • Добавлена поддержка для рециркулируемых (recyclable) ключей кэша с кэшированием фрагментов. (Pull Request)

  • Изменен формат ключа кэша для фрагментов, чтобы упростить отладку количества отказов (churn) ключа. (Pull Request)

  • AEAD зашифровывает куки и сессии с помощью GCM. (Pull Request)

  • Защита от подделка запроса по умолчанию. (Pull Request)

  • Принудительное истечение срока действия подписанных/зашифрованных куки на стороне сервера. (Pull Request)

  • Опция куки :expires поддерживает объект ActiveSupport::Duration. (Pull Request)

  • Использование зарегистрированной конфигурации сервера :puma в Capybara. (Pull Request)

  • Упрощены куки промежуточной программы с помощью поддержки ротации ключа. (Pull Request)

  • Добавлена возможность включения Early Hints для HTTP/2. (Pull Request)

  • Добавлена поддержка headless chrome для системных тестов. (Pull Request)

  • Добавлена опция :allow_other_host в метод redirect_back. (Pull Request)

  • Делает assert_recognizes для обхода монтированных engines. (Pull Request)

  • Добавлен DSL для конфигурирования заголовка Content-Security-Policy. (Pull Request, Commit, Commit)

  • Зарегистрированы самые популярные audio/video/font типы MIME, поддерживаемые современными браузерами. (Pull Request)

  • Изменен вывод результата дефолтного системного скриншота теста с inline на simple. (Commit)

  • Добавлена поддержка headless firefox для системных тестов. (Pull Request)

  • Добавлены безопасные X-Download-Options и X-Permitted-Cross-Domain-Policies в дефолтный набор заголовков. (Commit)

  • Изменены системные тесты для установки Puma как сервера по умолчанию, только если пользователь не указал вручную другой сервер. (Pull Request)

  • Добавлен заголовок Referrer-Policy в дефолтный набор заголовков. (Commit)

  • Совпадение поведения Hash#each Rails 5.2 с поведением в Rails 4 для ActionController::Parameters#each. (Pull Request)

  • Добавлена поддержка автоматического генератора nonce для Rails UJS. (Commit)

  • Обновлено дефолтное значение max-age в HSTS до 31536000 секунд (1 год), чтобы приспособиться к минимальному требованию max-age для https://hstspreload.org/. (Commit)

  • Добавлен метод псевдонима to_hash в to_h для cookies. Добавлен метод псевдонима to_h в to_hash для session. (Commit)

6. Action View

За подробностями обратитесь к Changelog.

6.1. Удалено

  • Удален устаревший обработчик Erubis ERB. (Commit)

6.2. Устарело

  • Устарел хелпер image_alt, который использовался для добавления дефолтного тега alt к изображениям, сгенерированным image_tag. (Pull Request)

6.3. Значимые изменения

  • Добавлен тип :json в auto_discovery_link_tag для поддержки ленты JSON. (Pull Request)

  • Добавлена опция srcset в хелпер image_tag. (Pull Request)

  • Исправлены проблемы с field_error_proc для optgroup оборачивания и выбора разделителя option. (Pull Request)

  • Изменен form_with, чтобы генерировать идентификаторы по умолчанию. (Commit)

  • Добавлен хелпер preload_link_tag. (Pull Request)

  • Разрешает использование вызываемых объектов как групповых методов для сгруппированных выборок. (Pull Request)

7. Action Mailer

За подробностями обратитесь к Changelog.

7.1. Значимые изменения

  • Разрешает классы Action Mailer для конфигурирования своего задания по доставке. (Pull Request)

  • Добавлен тестовый хелпер assert_enqueued_email_with. (Pull Request)

8. Active Record

За подробностями обратитесь к Changelog.

8.1. Удалено

  • Удален устаревший #migration_keys. (Pull Request)

  • Удалена устаревшая поддержка quoted_id при приведении типа (typecasting) объекта Active Record. (Commit)

  • Удален устаревший аргумент default из index_name_exists?. (Commit)

  • Удалена устаревшая поддержка для передачи класса :class_name в связях. (Commit)

  • Удалены устаревшие методы initialize_schema_migrations_table и initialize_internal_metadata_table. (Commit)

  • Удален устаревший метод supports_migrations?. (Commit)

  • Удален устаревший метод supports_primary_key?. (Commit)

  • Удален устаревший метод ActiveRecord::Migrator.schema_migrations_table_name. (Commit)

  • Удален устаревший аргумент name из #indexes. (Commit)

  • Удалены устаревшие аргументы из #verify!. (Commit)

  • Удалена устаревшая конфигурация .error_on_ignored_order_or_limit. (Commit)

  • Удален устаревший метод #scope_chain. (Commit)

  • Удален устаревший метод #sanitize_conditions. (Commit)

8.2. Устарело

  • Устарел supports_statement_cache?. (Pull Request)

  • Устарела одновременная передача аргументов и блока для count и sum в ActiveRecord::Calculations. (Pull Request)

  • Устарело делегирование для arel в Relation. (Pull Request)

  • Устарел метод set_state в TransactionState. (Commit)

  • Устарел expand_hash_conditions_for_aggregates без замены. (Commit)

8.3. Значимые изменения

  • При вызове динамических фикстур акцессор-метода без аргументов теперь возвращает все фикстуры этого типа. Ранее этот метод всегда возвращал пустой массив. (Pull Request)

  • Исправлена несогласованность с измененными атрибутами при переопределении ридер-атрибута Active Record. (Pull Request)

  • Поддержка убывающих индексов (descending indexes) для MySQL. (Pull Request)

  • Исправлена bin/rails db:forward для первой миграции. (Commit)

  • Вызов ошибки UnknownMigrationVersionError на движении (movement) миграций, когда текущая миграция не существует. (Commit)

  • Соблюдение SchemaDumper.ignore_tables в задачах rake для выгрузки структуры баз данных. (Pull Request)

  • Добавлен ActiveRecord::Base#cache_version, чтобы поддерживать рециркулируемые ключи кэша с помощью новых версий записей в ActiveSupport::Cache. Это также означает, что ActiveRecord::Base#cache_key теперь будет возвращать стабильный ключ, который больше не будет содержать временных меток. (Pull Request)

  • Предотвращено создание связанных параметров (bind param), если приведенное значение равно nil. (Pull Request)

  • Использование массового (bulk) INSERT для вставки фикстур для лучшей производительности. (Pull Request)

  • Слияние двух relations, представляющих вложенные joins, больше не преобразует joins слитого relation в LEFT OUTER JOIN. (Pull Request)

  • Раньше, если имелась вложенная транзакция и для внешней транзакции был сделан откат, запись из внутренней транзакции по-прежнему была бы отмечена как персистентная. Это было исправлено путем применения состояния родительской транзакции к дочерней транзакции, когда был сделан откат родительской транзакции. Это будет правильно отмечать записи из внутренней транзакции, поскольку они не являются персистентными. (Commit)

  • Исправлена ленивая загрузка/предварительная загрузка связи со скоупом, включающим joins. (Pull Request)

  • Предотвращены ошибки, вызванные подписчиками уведомлений sql.active_record, которые будут преобразованы к исключениям ActiveRecord::StatementInvalid. (Pull Request)

  • Пропуск кэширования запроса при работе с пакетом записей (find_each, find_in_batches, in_batches). (Commit)

  • Изменена булева сериализацию sqlite3 для использования 1 и 0. SQLite изначально распознает 1 и 0 как true и false, но не распознает 't' и 'f' как было сериализовано ранее. (Pull Request)

  • Значения, построенные с использованием многопараметрического назначения, теперь будут использовать значение post-type-cast для рендеринга в полях ввода формы единственного поля. (Commit)

  • ApplicationRecord больше не генерируется при генерации моделей. Если необходимо сгенерировать его, можно создать с помощью rails g application_record. (Pull Request)

  • Relation#or теперь принимает два relations, у которых разные значения только для references, так как references могут быть неявно вызваны where. (Commit)

  • При использовании Relation#or, извлекаются общие условия и помещаются они до условия OR. (Pull Request)

  • Добавлен метод хелпера binary для фикстур. (Pull Request)

  • Автоматическое угадывание обратных связей для STI. (Pull Request)

  • Добавлен новый класс ошибок LockWaitTimeout, который будет вызываться при превышении ожидания тайм-аута блокировки. (Pull Request)

  • Обновлены имена полезной нагрузки для инструментария sql.active_record, чтобы был более наглядным. (Pull Request)

  • Использование заданного алгоритма при убирании индекса из базы данных. (Pull Request)

  • Передача Set в Relation#where теперь ведет себя так же, как передача массива. (Commit)

  • PostgreSQL tsrange теперь сохраняет досекундную точность. (Pull Request)

  • Вызывается при вызове lock! в грязной (dirty) записи. (Commit)

  • Исправлена программная ошибка, при которой порядки столбцов для индекса не записывались в db/schema.rb, когда используется адаптер SQLite. (Pull Request)

  • Исправлен bin/rails db:migrate с указанной VERSION. bin/rails db:migrate с пустым VERSION ведет себя как без VERSION. Проверен формат VERSION: Разрешен номер версии миграции или имя файла миграции. Вызывается ошибка, если формат VERSION недействителен. Вызывается ошибка, если целевая миграция не существует. (Pull Request)

  • Добавлен новый класс ошибок StatementTimeout, который будет вызываться при превышении тайм-аута выражения. (Pull Request)

  • update_all теперь передает свои значения в Type#cast до передачи их в Type#serialize. Это означает, что update_all(foo: 'true') будет должным образом делать персистентным булево значение. (Commit)

  • Теперь требуется, чтобы фрагменты на чистом SQL были явно отмечены при использовании в методах запроса relation. (Commit, Commit)

  • Добавлен #up_only в миграции базы данных для кода, который актуален только для метода up в миграциях, например, для заполнения нового столбца. (Pull Request)

  • Добавлен новый класс ошибок QueryCanceled, который будет вызываться при отмене выражения из-за запроса пользователя. (Pull Request)

  • Теперь не разрешено определять скоупы, которые конфликтовали с методами экземпляра на Relation. (Pull Request)

  • Добавлена поддержка для классов оператора PostgreSQL в add_index. (Pull Request)

  • Логирование вызывающих методов запроса из базы данных. (Pull Request, Pull Request, Pull Request)

  • Неопределенные методы атрибута на потомках при сбросе информации о столбцах. (Pull Request)

  • Использование subselect для delete_all с limit или offset. (Commit)

  • Исправлена несогласованность с first(n) при использовании с limit(). Метод поиска first(n) теперь учитывает limit(), делает это в соответствии с relation.to_a.first(n), а также с поведением last(n). (Pull Request)

  • Исправлена вложенная связь has_many :through на неперсистентных экземплярах родителя. (Commit)

  • Принятие во внимание условий связи при удалении через записи. (Commit)

  • Не разрешает мутировать уничтоженный объект после вызова save или save!. (Commit)

  • Исправлена проблема слияния relation с помощью left_outer_joins. (Pull Request)

  • Поддержка внешних таблиц PostgreSQL. (Pull Request)

  • Очистка состояние транзакции, когда объект Active Record был дублирован (duped). (Pull Request)

  • Исправлена проблема не расширения при передаче объекта Array как аргумента методу where используя столбец composed_of. (Pull Request)

  • Делает вызов reflection.klass, если polymorphic? не будет использоваться. (Commit)

  • Исправлен #columns_for_distinct для MySQL и PostgreSQL, чтобы заставить ActiveRecord::FinderMethods#limited_ids_for использовать правильные значения первичного ключа, даже если столбцы ORDER BY включают первичный ключ другой таблицы. (Commit)

  • Исправлена проблема dependent: :destroy для отношений has_one/belongs_to, где родительский класс удалялся, когда дочернего не было. (Commit)

  • Простаивающие соединения с базой данных (ранее просто соединения без родительского процесса) теперь периодически закрываются с помощью connection pool reaper. (Commit)

9. Active Model

За подробностями обратитесь к Changelog.

9.1. Значимые изменения

  • Исправлены методы #keys, #values в ActiveModel::Errors. Изменен #keys, чтобы возвращал только ключи, у которых нет пустых сообщений. Изменен #values, чтобы возвращал только непустые значения. (Pull Request)

  • Добавлен метод #merge! для ActiveModel::Errors. (Pull Request)

  • Разрешает передачу Proc или Symbol в опции length валидатора. (Pull Request)

  • Теперь выполняется валидация ConfirmationValidator, когда значение _confirmation равно false. (Pull Request)

  • Модели, использующие API атрибутов с дефолтными proc, теперь могут быть маршализованы. (Commit)

  • Теперь не теряются все множественные :includes с опциями в сериализации. (Commit)

10. Active Support

За подробностями обратитесь к Changelog.

10.1. Удалено

  • Убраны устаревшие строковые фильтры :if и :unless для колбэков. (Commit)

  • Убрана устаревшая опция halt_callback_chains_on_return_false. (Commit)

10.2. Устарело

  • Устарел метод Module#reachable?. (Pull Request)

  • Устарел secrets.secret_token. (Commit)

10.3. Значимые изменения

  • Добавлен fetch_values для HashWithIndifferentAccess. (Pull Request)

  • Добавлена поддержка для :offset в Time#change. (Commit)

  • Добавлена поддержка для :offset и :zone в ActiveSupport::TimeWithZone#change. (Commit)

  • Пропуск имени гема и прогноз устаревания для уведомлений об устаревании. (Pull Request)

  • Добавлена поддержка для версионированных записей кэша. Это позволяет хранилищам кэша рециркулировать (recycle) ключи кэша, что значительно экономит на хранении в случаях с частым количеством отказов. Работает вместе с разделением #cache_key и #cache_version в Active Record и его использованием в кэшировании фрагмента Action Pack. (Pull Request)

  • Добавлен ActiveSupport::CurrentAttributes, чтобы предоставить тредоизолированные атрибуты синглтон. Основные случаи использования это удержание всех атрибутов каждого запроса легко доступными для всей системы. (Pull Request)

  • #singularize и #pluralize теперь учитывают неисчисляемые существительные для указанной локали. (Commit)

  • Добавлена дефолтная опция class_attribute. (Pull Request)

  • Добавлены Date#prev_occurring и Date#next_occurring, чтобы возвращать указанный следующий/предыдущий день недели. (Pull Request)

  • Добавлена опция default для атрибутов акцессоров модуля и класса. (Pull Request)

  • Кэш: write_multi. (Pull Request)

  • Теперь по умолчанию ActiveSupport::MessageEncryptor используется шифрование AES 256 GCM. (Pull Request)

  • Добавлен хелпер freeze_time, который замораживает время Time.now в тестах. (Pull Request)

  • Делает порядок элементов Hash#reverse_merge! в соответствии с HashWithIndifferentAccess. (Pull Request)

  • Добавлены поддержка назначения и истечения срока действия для ActiveSupport::MessageVerifier и ActiveSupport::MessageEncryptor. (Pull Request)

  • Обновлен String#camelize, чтобы предоставлять обратную связь передаче неправильной опции. (Pull Request)

  • Module#delegate_missing_to теперь вызывает DelegationError, если цель равна нулю, аналогично Module#delegate. (Pull Request)

  • Добавлены ActiveSupport::EncryptedFile и ActiveSupport::EncryptedConfiguration. (Pull Request)

  • Добавлен config/credentials.yml.enc, чтобы хранить секреты приложения в production. (Pull Request)

  • Добавлена поддержка ротации ключа в MessageEncryptor и MessageVerifier. (Pull Request)

  • Теперь возвращается экземпляр HashWithIndifferentAccess из HashWithIndifferentAccess#transform_keys. (Pull Request)

  • Hash#slice теперь вызывает встроенное определение Ruby 2.5+, если оно определено. (Commit)

  • IO#to_json теперь возвращает представление to_s, вместо того, чтобы пытаться преобразовать в массив. Это исправляет программную ошибку, в которой IO#to_json вызывает IOError при вызове нечитабельного объекта. (Pull Request)

  • Добавлена одинаковая сигнатура метода для Time#prev_day и Time#next_day в соответствии с Date#prev_day, Date#next_day. Разрешает аргумент для Time#prev_day и Time#next_day. (Commit)

  • Добавлена одинаковая сигнатура метода для Time#prev_month и Time#next_month в соответствии с Date#prev_month, Date#next_month. Разрешает аргумент для Time#prev_month и Time#next_month. (Commit)

  • Добавлена одинаковая сигнатура метода для Time#prev_year и Time#next_year в соответствии с Date#prev_year, Date#next_year. Разрешает аргумент для Time#prev_year и Time#next_year. (Commit)

  • Исправлена поддержка акронима в humanize. (Commit)

  • Разрешает Range#include? работать на интервалах TWZ. (Pull Request)

  • Кэш: Включено сжатие по умолчанию для значений > 1 Кб. (Pull Request)

  • Хранилище кэша Redis. (Pull Request, Pull Request)

  • Обрабатывает ошибки TZInfo::AmbiguousTime. (Pull Request)

  • MemCacheStore: Поддержка истечения сроков действия счетчиков. (Commit)

  • Теперь ActiveSupport::TimeZone.all возвращает только часовых поясов, находящихся в ActiveSupport::TimeZone::MAPPING. (Pull Request)

  • Изменяет поведение по умолчанию ActiveSupport::SecurityUtils.secure_compare, чтобы не отображать информацию об утечке даже для строки переменной длины. Переименован старый ActiveSupport::SecurityUtils.secure_compare в fixed_length_secure_compare, и начат вызов ArgumentError в случае несоответствия длины переданных строк. (Pull Request)

  • Теперь используется SHA-1 для генерации нечувствительных дайджестов, таких как заголовок ETag. (Pull Request, Pull Request)

  • assert_changes всегда будет утверждать, что выражение изменяется, вне зависимости от комбинаций аргументов from: и to:. (Pull Request)

  • Добавлен отсутствующий инструментарий для read_multi в ActiveSupport::Cache::Store. (Pull Request)

  • Поддержка хэша как первого аргумента в assert_difference. Это разрешает указать несколько числовых различий в одном утверждении. (Pull Request)

  • Кэширование: MemCache и Redis read_multi и ускорение (speedup) fetch_multi. Чтение из локального кэша, хранящегося в памяти до обращения к бэкенду. (Commit)

11. Active Job

За подробностями обратитесь к Changelog.

11.1. Значимые изменения

  • Разрешить передачу блока в ActiveJob::Base.discard_on, чтобы разрешить собственную обработку заданий сброса. (Pull Request)

12. Руководства Ruby on Rails

За подробностями обратитесь к Changelog.

12.1. Значимые изменения

13. Благодарности

Взгляните на полный список контрибьюторов Rails, на людей, которые потратили много часов, сделав Rails стабильнее и надёжнее. Спасибо им всем.