Ключевые новинки в Rails 7.1:
Прежде чем апгрейднуть существующее приложение, было бы хорошо иметь перед этим покрытие тестами. Также, до попытки обновиться до Rails 7.1, необходимо сначала произвести апгрейд до Rails 7.0 и убедиться, что приложение все еще выполняется так, как нужно. Список вещей, которые нужно выполнить для апгрейда доступен в руководстве Апгрейд Ruby on Rails.
Поддержка Docker по умолчанию для новых приложений rails. При генерации нового приложения, Rails теперь включит файлы для Docker в приложение.
Эти файлы служат основополагающей настройкой для развертывания вашего приложения Rails в среде production с помощью Docker. Важно отметить, что эти файлы не предназначены для целей разработки.
Вот быстрый пример того, как собрать и запустить ваше приложение Rails с помощью этих файлов Docker:
$ docker build -t app .
$ docker volume create app-storage
$ docker run --rm -it -v app-storage:/rails/storage -p 3000:3000 --env RAILS_MASTER_KEY=<your-config-master-key> app
Также из этого образа Docker можно запустить console или runner:
$ docker run --rm -it -v app-storage:/rails/storage --env RAILS_MASTER_KEY=<your-config-master-key> app console
Те, кто ищет, как создать мультиплатформенный образ (например, развертывание на Apple Silicon для AMD или Intel), и передать его на Docker Hub, следуйте этим шагам:
$ docker login -u <your-user>
$ docker buildx create --use
$ docker buildx build --push --platform=linux/amd64,linux/arm64 -t <your-user/image-name> .
Это улучшение упрощает процесс развертывания, предоставляя удобную стартовую точку для поднятия и запуска вашего приложения Rails в среде production.
ActiveRecord::Base.normalizes
ActiveRecord::Base.normalizes
объявляет нормализацию атрибутов. Нормализация применяется, когда атрибут назначается или обновляется, и нормализованное значение будет записано в базу данных. Нормализация также применяется к соответствующему аргументу с ключом в методах запроса, позволяя запрашивать записи с помощью неформализованных значений.
Например:
class User < ActiveRecord::Base
normalizes :email, with: -> email { email.strip.downcase }
normalizes :phone, with: -> phone { phone.delete("^0-9").delete_prefix("1") }
end
user = User.create(email: " CRUISE-CONTROL@EXAMPLE.COM\n")
user.email # => "cruise-control@example.com"
user = User.find_by(email: "\tCRUISE-CONTROL@EXAMPLE.COM ")
user.email # => "cruise-control@example.com"
user.email_before_type_cast # => "cruise-control@example.com"
User.where(email: "\tCRUISE-CONTROL@EXAMPLE.COM ").count # => 1
User.where(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]).count # => 0
User.exists?(email: "\tCRUISE-CONTROL@EXAMPLE.COM ") # => true
User.exists?(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]) # => false
User.normalize_value_for(:phone, "+1 (555) 867-5309") # => "5558675309"
ActiveRecord::Base.generates_token_for
ActiveRecord::Base.generates_token_for
определяет генерацию токенов для определенной цели. Сгенерированные токены могут стать просроченными, а также содержать данные записи. При использовании токена для получения записи, будут сравнены данные из токена и данные из записи. Если они не совпадут, токен будет считаться невалидным, и то же самое, если он просрочен.
Вот пример реализации одноразового токена сброса пароля:
class User < ActiveRecord::Base
has_secure_password
generates_token_for :password_reset, expires_in: 15.minutes do
# `password_salt` (определенный `has_secure_password`) возвращает соль для
# пароля. Соль изменяется при изменении пароля, таким образом, токен
# будет просрочен, если пароль изменится.
password_salt&.last(10)
end
end
user = User.first
token = user.generate_token_for(:password_reset)
User.find_by_token_for(:password_reset, token) # => user
user.update!(password: "new password")
User.find_by_token_for(:password_reset, token) # => nil
perform_all_later
, чтобы поместит в очередь несколько заданий за разМетод perform_all_later
в Active Job разработан, чтобы упростить процесс помещения в очередь нескольких заданий одновременно. Это мощное дополнение позволяет эффективно помещать задания в очередь без запуска колбэков. Это в особенности полезно, когда необходимо поместить набор заданий в очередь за раз, что уменьшает накладные расходы на несколько запросов к хранилищу данных очереди.
Вот как можно воспользоваться преимуществом perform_all_later
:
# Постановка в очередь отдельных заданий
ActiveJob.perform_all_later(MyJob.new("hello", 42), MyJob.new("world", 0))
# Постановка в очередь моссива заданий
user_jobs = User.pluck(:id).map { |id| UserJob.new(user_id: id) }
ActiveJob.perform_all_later(user_jobs)
Пользуясь perform_all_later
, можно оптимизировать процесс постановки заданий в очередь и пользоваться преимуществом улучшенной эффективности, в особенности при работе с большими наборами заданий. Стоит отметить, что в адаптерах очереди, поддерживающих новый метод enqueue_all
, таких как адаптер Sidekiq, процесс постановки в очередь еще более оптимизирован с помощью push_bulk
.
Предупреждаем, что этот новый метод представляет отдельное событие, enqueue_all.active_job
, и не использует существующее событие enqueue.active_job
. С помощью этого достигается точное отслеживание и отчетность о процессе массовой постановки в очередь.
Составные первичные ключи теперь поддерживаются и на уровне базы данных, и приложения. Rails способен извлечь эти ключи напрямую из схемы. Эта функция особенно полезна для отношений many-to-many и других сложных моделей данных, когда единственного столбца недостаточно для уникальной идентификации записи.
SQL, генерируемый методами запроса в Active Record (например, #reload
, #update
, #delete
) будет содержать все части составного первичного ключа. Методы, наподобие #first
и #last
, будут использовать полный составной первичный ключ в выражениях ORDER BY
.
Можно использовать макрос query_constraints
в качестве "виртуального первичного ключа", чтобы достичь того же поведения без изменения схемы базы данных. Пример:
class TravelRoute < ActiveRecord::Base
query_constraints :origin, :destination
end
Схожим образом связи принимают опцию query_constraints:
. Эта опция служит в качестве составного внешнего ключа, настраивая список столбцов, используемых для доступа к связанной записи.
Example:
class TravelRouteReview < ActiveRecord::Base
belongs_to :travel_route, query_constraints: [:travel_route_origin, :travel_route_destination]
end
Trilogy
Был представлен новый адаптер для содействия бесшовной интеграции Trilogy
, клиента базы данных, совместимой с MySQL, с приложением Rails. Теперь у приложений Rails есть вариант включения функционала Trilogy
, настраивая их файл config/database.yml
. К примеру:
development:
adapter: trilogy
database: blog_development
pool: 5
Альтернативно можно достичь интеграции с помощью переменной среды DATABASE_URL
:
ENV['DATABASE_URL'] # => "trilogy://localhost/blog_development?pool=5"
ActiveSupport::MessagePack
ActiveSupport::MessagePack
это сериализатор, интегрированный с гемом msgpack
. ActiveSupport::MessagePack
может сериализовывать базовые типы Ruby, поддерживаемые msgpack
, а также несколько дополнительных типов, таких как Time
, ActiveSupport::TimeWithZone
и ActiveSupport::HashWithIndifferentAccess
.
По сравнению с JSON
и Marshal
, ActiveSupport::MessagePack
может уменьшить размер полезной нагрузки и улучшить производительность.
ActiveSupport::MessagePack
можно использовать в качестве сериализатора сообщения:
config.active_support.message_serializer = :message_pack
# Или отдельно:
ActiveSupport::MessageEncryptor.new(secret, serializer: :message_pack)
ActiveSupport::MessageVerifier.new(secret, serializer: :message_pack)
В качестве сериализатора куки:
config.action_dispatch.cookies_serializer = :message_pack
И в качестве сериализатора кэша:
config.cache_store = :file_store, "tmp/cache", { serializer: :message_pack }
# Или отдельно:
ActiveSupport::Cache.lookup_store(:file_store, "tmp/cache", serializer: :message_pack)
config.autoload_lib
и config.autoload_lib_once
для улучшенной автоматической загрузкиБыл представлен новый конфигурационный метод, config.autoload_lib(ignore:)
. Этот метод используется для улучшения путей автозагрузки приложений, с помощью включения директории lib
, которая по умолчанию не включена. А также для новых приложений генерируется config.autoload_lib(ignore: %w(assets tasks))
.
При вызове из config/application.rb
, либо config/environments/*.rb
, этот метод добавляет директорию lib
в config.autoload_paths
и config.eager_load_paths
. Важно отметить, что эта особенность не доступно для engine.
Для обеспечения гибкости можно использовать ключевой аргумент ignore
, чтобы указать поддиректории в директории lib
, которые не должны управляться автозагрузчиками. К примеру, можно исключить директории, такие как assets
, tasks
и generators
, передав их в качестве аргумента ignore
:
config.autoload_lib(ignore: %w(assets tasks generators))
Метод config.autoload_lib_once
подобен config.autoload_lib
, за исключением того, что он добавляет lib
в config.autoload_once_paths
.
За подробностями обратитесь к руководству по автоматической загрузке
Было представлено значительное улучшение для Active Record API, расширяющее его поддержку асинхронных запросов. Это улучшение посвящено необходимости более эффективной обработки не очень быстрых запросов, в частности фокусируясь на аггрегирующих (таких как count
, sum
и т.д.) и всех методах, возвращающих единственную запись, или что-то отличающееся от Relation
.
Новый API включает следующие асинхронные методы:
async_count
async_sum
async_minimum
async_maximum
async_average
async_pluck
async_pick
async_ids
async_find_by_sql
async_count_by_sql
Вот краткий пример того, как использовать один из этих методов, async_count
, чтобы подсчитать количество опубликованных сообщений асинхронным образом:
# Синхронный подсчет
published_count = Post.where(published: true).count # => 10
# Асинхронный подсчет
promise = Post.where(published: true).async_count # => #<ActiveRecord::Promise status=pending>
promise.value # => 10
Эти методы позволяют запускать эти операции асинхронным образом, что может значительно улучшить эффективность определенных типов запросов к базе данных.
locals
Представлена новая особенность, позволяющая шаблонам устанавливать явные locals
. Это улучшение предоставляет большее управление и ясность при передаче переменных в ваши шаблоны.
По умолчанию шаблоны принимают любые locals
как ключевые аргументы. Однако, теперь можно определить, какие locals
шаблон должен принимать, добавляя магический комментарий locals
в начале файла шаблона.
Вот как это работает:
<%# locals: (message:) -%>
<%= message %>
Также можно установить значения по умолчанию для этих локальных переменных:
<%# locals: (message: "Hello, world!") -%>
<%= message %>
Если хотите отключить использование локальных переменных полностью, это можно сделать так:
<%# locals: () %>
Rails.application.deprecators
Новый метод Rails.application.deprecators
возвращает коллекцию управляемых депрекаторов в вашем приложении и позволяет добавлять и получать отдельные депрекаторы:
Rails.application.deprecators[:my_gem] = ActiveSupport::Deprecation.new("2.0", "MyGem")
Rails.application.deprecators[:other_gem] = ActiveSupport::Deprecation.new("3.0", "OtherGem")
Конфигурационные настройки коллекции влияют на все депрекаторы в коллекции.
Rails.application.deprecators.debug = true
Rails.application.deprecators[:my_gem].debug
# => true
Rails.application.deprecators[:other_gem].debug
# => true
Есть сценарии, в которых нужно приглушить все сообщения об устаревании для определенного блока кода. С помощью коллекции депрекаторов возможно с легкостью заглушить все предупреждения депрекаторов в пределах блока:
Rails.application.deprecators.silence do
Rails.application.deprecators[:my_gem].warn # Нет предупреждения (заглушено)
Rails.application.deprecators[:other_gem].warn # Нет предупреждения (заглушено)
end
response.parsed_body
Когда блоки тестов ActionDispatch::IntegrationTest
вызывают response.parsed_body
для откликов JSON, их полезная нагрузка будет доступна с indifferent access. Это включает интеграцию с Pattern Matching в Ruby, и встроенной поддержкой Minitest для pattern matching:
get "/posts.json"
response.content_type # => "application/json; charset=utf-8"
response.parsed_body.class # => Array
response.parsed_body # => [{"id"=>42, "title"=>"Title"},...
assert_pattern { response.parsed_body => [{ id: 42 }] }
get "/posts/42.json"
response.content_type # => "application/json; charset=utf-8"
response.parsed_body.class # => ActiveSupport::HashWithIndifferentAccess
response.parsed_body # => {"id"=>42, "title"=>"Title"}
assert_pattern { response.parsed_body => [{ title: /title/i }] }
response.parsed_body
, чтобы парсить HTML с помощью NokogiriРасширен модуль ActionDispatch::Testing
, чтобы поддерживать парсинг значения HTML response.body
в экземпляр Nokogiri::HTML5::Document
:
get "/posts"
response.content_type # => "text/html; charset=utf-8"
response.parsed_body.class # => Nokogiri::HTML5::Document
response.parsed_body.to_html # => "<!DOCTYPE html>\n<html>\n..."
Недавно добавленная поддержка Nokogiri для pattern matching, вместе со встроенной поддержкой Minitest для pattern matching представляют возможности для тестовых утверждений о структуре и содержимом отклика HTML:
get "/posts"
html = response.parsed_body # => <html>
# <head></head>
# <body>
# <main><h1>Some main content</h1></main>
# </body>
# </html>
assert_pattern { html.at("main") => { content: "Some main content" } }
assert_pattern { html.at("main") => { content: /content/ } }
assert_pattern { html.at("main") => { children: [{ name: "h1", content: /content/ }] } }
ActionView::TestCase.register_parser
Расширен ActionView::TestCase
для поддержки парсинга содержимого, отрендеренного партиалами вью, в известные структуры. По умолчанию определяет rendered_html
для парсинга HTML в Nokogiri::XML::Node
и rendered_json
для парсинга JSON в ActiveSupport::HashWithIndifferentAccess
:
test "renders HTML" do
article = Article.create!(title: "Hello, world")
render partial: "articles/article", locals: { article: article }
assert_pattern { rendered_html.at("main h1") => { content: "Hello, world" } }
end
test "renders JSON" do
article = Article.create!(title: "Hello, world")
render formats: :json, partial: "articles/article", locals: { article: article }
assert_pattern { rendered_json => { title: "Hello, world" } }
end
Чтобы парсить отрендеренное содержимое в RSS, зарегистрируйте вызов к RSS::Parser.parse
:
register_parser :rss, -> rendered { RSS::Parser.parse(rendered) }
test "renders RSS" do
article = Article.create!(title: "Hello, world")
render formats: :rss, partial: article, locals: { article: article }
assert_equal "Hello, world", rendered_rss.items.last.title
end
Чтобы парсить отрендеренное содержимое в Capybara::Simple::Node, перерегистрируйте парсер :html
с помощью вызова к Capybara.string
:
register_parser :html, -> rendered { Capybara.string(rendered) }
test "renders HTML" do
article = Article.create!(title: "Hello, world")
render partial: article
rendered_html.assert_css "main h1", text: "Hello, world"
end
За подробностями обратитесь к Changelog.
Удалена устаревшая команда bin/rails secrets:setup
.
Удален заголовок по умолчанию X-Download-Options
, так как он использовался только Internet Explorer.
Устарело использование Rails.application.secrets
.
Устарели команды secrets:show
и secrets:edit
в пользу credentials
.
Устарел Rails::Generators::Testing::Behaviour
в пользу Rails::Generators::Testing::Behavior
.
Добавлена опция sandbox_by_default
, чтобы запускать консоль rails в режиме песочницы по умолчанию.
Добавлен новый синтаксис для поддержки фильтрации тестов по диапазону строк.
Добавлена опция DATABASE
, включающая определение целевой базы данных при запуске команды rails railties:install:migrations
, чтобы скопировать миграции.
Добавлена поддержка Bun в генераторе rails new --javascript
.
$ rails new my_new_app --javascript=bun
Добавлена возможность показывать медленные тесты запускающему тесты.
За подробностями обратитесь к Changelog.
Добавлен тестовый вспомогательный метод capture_broadcasts
для отлова всех сообщений, транслируемых в блоке.
Добавлена возможность адаптеру Redis для pub/sub автоматически пересоединяться, когда соединение Redis потеряно.
Добавлены управляющие колбэки before_command
, after_command
и around_command
к ActionCable::Connection::Base
.
За подробностями обратитесь к Changelog.
Удалено устаревшее поведение у Request#content_type
Удалена устаревшая возможность присвоения одиночного значения config.action_dispatch.trusted_proxies
.
Удалена регистрация устаревших драйверов poltergeist
и webkit
(capybara-webkit) для системного тестирования.
Устарел config.action_dispatch.return_only_request_media_type_on_content_type
.
Устарел AbstractController::Helpers::MissingHelperError
.
Устарел ActionDispatch::IllegalStateError
.
Устарели директивы политики разрешений speaker
, vibrate
и vr
.
Устарели значения true
и false
для config.action_dispatch.show_exceptions
в пользу :all
, :rescuable
или :none
.
Добавлен метод exclude?
в ActionController::Parameters
. Он противоположен методу include?
.
Добавлен метод ActionController::Parameters#extract_value
, чтобы позволять извлечение сериализуемы значений из параметров.
Добавлена возможность использования пользовательской логики для хранения и получения токенов CSRF.
Добавлены ключевые аргументы html
и screenshot
для вспомогательного метода системного тестирования скриншотов.
За подробностями обратитесь к Changelog.
Удалена устаревшая константа ActionView::Path
.
Удалена устаревшая поддержка передачи переменных экземпляра как локальных в партиалы.
check_box_tag
и radio_button_tag
теперь принимают checked
как ключевой аргумент.
Добавлен вспомогательный метод picture_tag
, чтобы генерировать теги HTML <picture>
.
Вспомогательный метод simple_format
теперь принимает функционал :sanitize_options
, позволяя добавление дополнительных опций для процесса обработки.
simple_format("<a target=\"_blank\" href=\"http://example.com\">Continue</a>", {}, { sanitize_options: { attributes: %w[target href] } })
# => "<p><a target=\"_blank\" href=\"http://example.com\">Continue</a></p>"
За подробностями обратитесь к Changelog.
Устарел config.action_mailer.preview_path
.
Устарела передача параметров в assert_enqueued_email_with
с помощью ключевого аргумента :args
. Теперь поддерживается ключевой аргумент :params
, используйте его для передачи параметров.
Добавлен config.action_mailer.preview_paths
для поддержки нескольких путей предварительного просмотра.
Добавлен capture_emails
в тестовые вспомогательные методы, чтобы для отлова всех писем, отправленных в блоке.
Добавлен deliver_enqueued_emails
к ActionMailer::TestHelper
для доставки всех отложенных заданий почты.
За подробностями обратитесь к Changelog.
Удалена поддержка ActiveRecord.legacy_connection_handling
.
Удалены устаревшие методы доступа конфигурации ActiveRecord::Base
Удалена поддержка :include_replicas
у configs_for
. Вместо него используйте :include_hidden
.
Удален устаревший config.active_record.partial_writes
.
Удален устаревший Tasks::DatabaseTasks.schema_file_type
.
Убран флажок --no-comments
в структурных выгрузках для PostgreSQL.
Устарел аргумент name
у #remove_connection
.
Устарел check_pending!
в пользу check_all_pending!
.
Устарела опция deferrable: true
у add_foreign_key
в пользу deferrable: :immediate
.
Устарел TestFixtures#fixture_path
в пользу TestFixtures#fixture_paths
.
Устарела делегация из Base
к connection_handler
.
Устарела config.active_record.suppress_multiple_database_warning
.
Устарело использование ActiveSupport::Duration
в качестве интерполируемого связанного параметра в строковом шаблоне SQL.
Устарел all_connection_pools
и connection_pool_list
сделан более явным.
Устарело, что read_attribute(:id)
возвращает первичный ключ, если первичный ключ не :id
.
Устарел аргумент rewhere
у #merge
.
Устарело создание псевдонимов не-атрибутов с помощью alias_attribute
.
Добавлен TestFixtures#fixture_paths
для поддержки нескольких путей фикстур.
Добавлен authenticate_by
при использовании has_secure_password
.
Добавлен update_attribute!
к ActiveRecord::Persistence
, похожий на update_attribute
, но вызывающий ActiveRecord::RecordNotSaved
, если колбэк before_*
выкидывает :abort
.
Разрешено использование псевдонимов атрибутов в insert_all
/upsert_all
.
Добавлена опция :include
к add_index
.
Добавлен метод запроса #regroup
, как сокращение для .unscope(:group).group(fields)
.
Добавлена поддержка автозаполняемых столбцов и произвольных первичных ключей адаптеру SQLite3
.
Добавлены современные производительные значения по умолчанию для соединений с базой данных SQLite3
.
Разрешено указывать выражения where с синтаксисом кортежа столбцов.
Topic.where([:title, :author_name] => [["The Alchemist", "Paulo Coelho"], ["Harry Potter", "J.K Rowling"]])
Автоматически генерируемые имена индексов теперь ограничены 62 байтами, что вписывается в лимиты длины имени индекса по умолчанию для MySQL, PostgreSQL и SQLite.
Представлен адаптер для клиента базы данных Trilogy.
Добавлен метод ActiveRecord.disconnect_all!
для немедленного закрытия всех соединений у всех пулов.
Добавлены команды миграции PostgreSQL для переименования enum, добавления значения и переименования значения.
Добавлен псевдоним ActiveRecord::Base#id_value
для доступа к необработанному значению столбца id записи.
Добавлена опция валидации для enum
.
За подробностями обратитесь к Changelog.
Удалены устаревшие неправильные типы содержимого в конфигурациях Active Storage.
Удалены устаревшие методы ActiveStorage::Current#host
и ActiveStorage::Current#host=
.
Удалено устаревшие поведение при присвоении коллекции вложений. Вместо добавления к коллекции, сейчас коллекция заменяется.
Удалены устаревшие методы purge
и purge_later
из связи с вложениями.
ActiveStorage::Analyzer::AudioAnalyzer
теперь выводит sample_rate
и tags
в хэше вывода metadata
.
Добавлена опция использования предопределенных вариантов при вызове методов preview
или representation
на вложении.
Добавлена опция preprocessed
при объявлении вариантов к предобработанным вариантам.
Добавлена возможность уничтожать варианты Active Storage.
User.first.avatar.variant(resize_to_limit: [100, 100]).destroy
За подробностями обратитесь к Changelog.
Добавлена поддержка бесконечных рядов в опции LengthValidator
:in
/:within
.
validates_length_of :first_name, in: ..30
Добавлена поддержка безначальных рядов в валидаторах inclusivity/exclusivity
.
validates_inclusion_of :birth_date, in: -> { (..Date.today) }
validates_exclusion_of :birth_date, in: -> { (..Date.today) }
Добавлена поддержка для вызовов (challenges) пароля в has_secure_password
. Когда установлена, проверяет, что вызов пароля соответствует сохраненному password_digest
.
Разрешает валидаторам принимать lambda без аргумента записи.
# До
validates_comparison_of :birth_date, less_than_or_equal_to: ->(_record) { Date.today }
# После
validates_comparison_of :birth_date, less_than_or_equal_to: -> { Date.today }
За подробностями обратитесь к Changelog.
Удалено устаревшее переопределение Enumerable#sum
.
Удален устаревший ActiveSupport::PerThreadRegistry
.
Удалены устаревшие опции для передачи формата в #to_s
в Array
, Range
, Date
, DateTime
, Time
, BigDecimal
, Float
и Integer
.
Удалено устаревшее переопределение ActiveSupport::TimeWithZone.name
.
Удален устаревший файл active_support/core_ext/uri
.
Удален устаревший файл active_support/core_ext/range/include_time_with_zone
.
Удалено неявное преобразование объектов в String
в ActiveSupport::SafeBuffer
.
Удалена устаревшая поддержка генерации несоответствующих RFC 4122 UUID при предоставлении ID пространства имен, не являющегося одной из констант, определенных в Digest::UUID
.
Устарел config.active_support.disable_to_s_conversion
.
Устарел config.active_support.remove_deprecated_time_with_zone_name
.
Устарел config.active_support.use_rfc4122_namespaced_uuids
.
Устарел SafeBuffer#clone_empty
.
Устарело использование синглтона ActiveSupport::Deprecation
.
Устарела инициализация ActiveSupport::Cache::MemCacheStore
с помощью экземпляра Dalli::Client
.
Устарели методы Notification::Event
#children
и #parent_of?
.
За подробностями обратитесь к Changelog.
QueAdapter
.
Добавлен perform_all_later
для постановки в очередь нескольких задания за раз.
Добавлена опция --parent
к генератору задания, чтобы указать родительский класс задания.
Добавлен метод after_discard
к ActiveJob::Base
, чтобы запустить колбэк, перед тем, как задание будет сброшено.
Добавлена поддержка логирования вызова добавления в очередь фонового задания.
За подробностями обратитесь к Changelog.
За подробностями обратитесь к Changelog.
Добавлены адреса X-Forwarded-To
к получателям.
Добавлен метод bounce_now_with
к ActionMailbox::Base
, чтобы посылать возвращенное письмо без прохождения через очередь рассыльщика.
За подробностями обратитесь к Changelog.
Взгляните на полный список контрибьюторов Rails, на людей, которые потратили много часов, сделав Rails стабильнее и надёжнее. Спасибо им всем.