Заметки о релизе Ruby on Rails 4.2
Ключевые новинки в Rails 4.2:
- Active Job
- Асинхронные письма
- Adequate Record
- Веб-консоль
- Поддержка внешних ключей
Эти заметки о релизе покрывают только основные обновления. Чтобы узнать о других обновлениях, различных багфиксах и изменениях, обратитесь к логам изменений или к списку коммитов в главном репозитории Rails на GitHub.
Обновление до Rails 4.2
Если вы обновляете существующее приложение, было бы хорошо иметь перед этим покрытие тестами. Также, до попытки обновиться до Rails 4.2, необходимо сначала обновиться до Rails 4.1 и убедиться, что приложение все еще выполняется так, как нужно. Список вещей, которые нужно выполнить для обновления доступен в руководстве Обновление Rails.
Основные изменения
Active Job
Active Job — это новый фреймворк в Rails 4.2. Это обычный интерфейс для систем очередей, таких как Resque, Delayed Job, Sidekiq и так далее.
Задания, написанные с помощью Active Job API, запускаются в любой поддерживаемой очереди благодаря их соответствующим адаптерам. Active Job поставляется преднастроенным с встроенным исполнителем, выполняющим задания сразу.
Часто заданиям необходимо принимать объекты Active Record в качестве аргументов. Active Job передает ссылки на объект как URI (единые идентификаторы ресурса) вместо маршализации самого объекта. Новая библиотека Global ID создает URI и ищет объекты, на которые они ссылаются. Передача объектов Active Record как атрибутов задания внутри устроена как использование Global ID.
Например, если trashable
это объект Active Record, тогда это задание будет запускаться без необходимости сериализации:
class TrashableCleanupJob < ActiveJob::Base
def perform(trashable, depth)
trashable.cleanup(depth)
end
end
За подробностями обратитесь к руководству по основам Active Job.
Асинхронные письма
Созданный на основе Active Job, сейчас Action Mailer имеет метод #deliver_later
, добавляющий отсылку вашего письма с помощью очереди, таким образом, не блокируя контроллер или модель. если очередь асинхронная (встроенная очередь по умолчанию будет блокировать).
Отсылка писем прямо сейчас все еще возможна с помощью deliver_now
.
Adequate Record
Adequate Record — это набор улучшений производительности в Active Record, сделавший обычные вызовы методов find
и find_by
и некоторых запросов связей до двух раз быстрее.
Он работает, кэшируя обычные запросы SQL как подготовленные выражения (prepared statements) и повторно используя их при подобных вызовах, опуская большую часть работы по генерации запроса при последующих вызовах. За подробностями обратитесь к публикации Aaron Patterson.
Active Record будет пользоваться преимуществами этой особенности на поддерживаемых операциях автоматически, без какого-либо вовлечения пользователя или изменения кода. Вот несколько примеров поддерживаемых операций:
Post.find(1) # Первый вызов генерирует и кэширует подготовленное выражение
Post.find(2) # Последующие вызовы повторно используют закэшированное подготовленное выражение
Post.find_by_title('first post')
Post.find_by_title('second post')
Post.find_by(title: 'first post')
Post.find_by(title: 'second post')
post.comments
post.comments(true)
Важно подчеркнуть то, что, как подчеркивают вышеприведенные примеры, подготовленные выражения не кэшируют значения, переданные в вызов метода, они только являются шаблонами для них.
Кэширование не используется в следующих сценариях:
- В модели есть скоуп по умолчанию
- Модель использует наследование с единой таблицей (STI)
find
со списком ids. Т.е.:# не кэшируются Post.find(1,2,3) Post.find([1,2])
find_by
с фрагментом SQL:Post.find_by('published_at < ?', 2.weeks.ago)
Веб-консоль
Новые приложения, генерируемые начиная с Rails 4.2, поставляются с гемом Web Console по умолчанию. Веб-консоль добавляет интерактивную консоль Ruby на каждой странице ошибки и хелпер вьюх и контроллеров console
.
Интерактивная консоль на страницах ошибок позволяет выполнять код в контексте места, где было вызвано исключение. Хелпер вьюх console
при вызове в любом месте вьюхи или контроллера запускает интерактивную консоль в последнем контексте, как только завершится рендеринг.
Поддержка внешних ключей
DSL миграций теперь поддерживает добавление или удаление внешних ключей. Также они выгружаются в schema.rb
. В настоящее время внешние ключи поддерживаются только адаптерами mysql
, mysql2
и postgresql
.
# добавляет внешний ключ на `articles.author_id`, ссылающийся на `authors.id`
add_foreign_key :articles, :authors
# добавляет внешний ключ на `articles.author_id`, ссылающийся на `users.lng_id`
add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
# удаляет внешний ключ на `accounts.branch_id`
remove_foreign_key :accounts, :branches
# удаляет внешний ключ на `accounts.owner_id`
remove_foreign_key :accounts, column: :owner_id
Смотрите полное описание в документации API для add_foreign_key и remove_foreign_key.
Несовместимости
Ранее устаревшая функциональность была убрана. Обратитесь к отдельным компонентам за информацией о новых устареваниях в этом релизе.
Следующие изменения требуют немедленных действий при обновлении.
render
со строковым аргументом
Раньше вызов в контроллере render "foo/bar"
был эквивалентом render file: "foo/bar"
. В Rails 4.2 это стало означать render template: "foo/bar"
. Если нужно рендерить файл, измените свой код на использования явной формы (render file: "foo/bar"
).
respond_with
/ метод класса respond_to
Методы respond_with
и соответствующий метод класса respond_to
были перемещены в гем responders. Добавьте gem 'responders', '~> 2.0'
в свой Gemfile
для использования:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
respond_to :html, :json
def show
@user = User.find(params[:id])
respond_with @user
end
end
Метод экземпляра respond_to
не был затронут:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
respond_to do |format|
format.html
format.json { render json: @user }
end
end
end
Хост по умолчанию для rails server
Из-за изменения в Rack, по умолчанию rails server
теперь ждет запросов на localhost
вместо 0.0.0.0
. Это минимально затрагивает стандартный процесс разработки, так как и http://127.0.0.1:3000, и http://localhost:3000 будут работать, как и прежде на вашей машине.
Однако, это изменение не позволяет доступ к серверу Rails с другой машины, например, если ваша среда разработки в виртуальной машине, и вы хотите доступ к ней с хоста. В таких случаях запускайте сервер с помощью rails server -b 0.0.0.0
, чтобы восстановить старое поведение.
Если так сделаете, не забудьте правильно настроить свой файервол, чтобы только доверенные машины вашей сети имели доступ к вашему серверу разработки.
Изменены символы для опции статуса у render
Из-за изменения в Rack, символы, которые метод render
принимает для опции :status
, были изменены:
- 306:
:reserved
был убран. - 413:
:request_entity_too_large
был переименован в:payload_too_large
. - 414:
:request_uri_too_long
был переименован в:uri_too_long
. - 416:
:requested_range_not_satisfiable
был переименован в:range_not_satisfiable
.
Имейте в виду, что если вызывается render
с неизвестным символом, статус отклика будет по умолчанию 500.
Санитайзер HTML
Санитайзер HTML был заменен новой, более надежной, реализацией, созданной на основе Loofah и Nokogiri. Новый санитайзер более безопасный и его санация более мощная и гибкая.
Из-за нового алгоритма, санированный результат может быть различным для определенных патологических входных данных.
Если у вас есть особая необходимость в точном результате от старого санитайзера , можете добавить гем rails-deprecated_sanitizer в свой Gemfile, и получите старое поведение. Этот гем не будет выдавать предостережения об устаревании, поскольку он опциональный.
rails-deprecated_sanitizer
будет поддерживаться только для Rails 4.2; он не будет поддерживаться для Rails 5.0.
Подробнее об изменениях в новом санитайзере смотрите эту публикацию в блоге.
assert_select
assert_select
теперь базируется на Nokogiri.
В результате некоторые ранее валидные селекторы теперь не поддерживаются. Если ваше приложение использует любое из этих написаний, их нужно обновить:
Значения в селекторах атрибутов необходимо заключать в кавычки, если они содержат не буквенно-цифровые символы.
# до a[href=/] a[href$=/] # теперь a[href="/"] a[href$="/"]
DOM, созданные из источника HTML, содержащего невалидный HTML с неправильно вложенными элементами, могут отличаться.
Например:
# содержимое: <div><i><p></i></div> # раньше: assert_select('div > i') # => true assert_select('div > p') # => false assert_select('i > p') # => true # сейчас: assert_select('div > i') # => true assert_select('div > p') # => true assert_select('i > p') # => false
Если выбираемые данные содержат сущности, значение для сравнения раньше было чистым (т.е.
AT&T
), а сейчас вычисленное (т.е.AT&T
).# содержимое: <p>AT&T</p> # раньше: assert_select('p', 'AT&T') # => true assert_select('p', 'AT&T') # => false # сейчас: assert_select('p', 'AT&T') # => true assert_select('p', 'AT&T') # => false
Кроме того, у замен изменился синтаксис.
Теперь можно использовать селектор :match
, схожий с CSS:
assert_select ":match('id', ?)", 'comment_1'
Кроме того, замены Regexp выглядят иначе, когда проваливается оператор контроля. Обратите внимание, как /hello/
тут:
assert_select(":match('id', ?)", /hello/)
становится "(?-mix:hello)"
:
Expected at least 1 element matching "div:match('id', "(?-mix:hello)")", found 0..
Expected 0 to be >= 1.
Подробнее об assert_select
смотрите в документации по тестированию Dom в Rails.
Railties
За подробностями обратитесь к Changelog.
Удалено
Опция
--skip-action-view
была убрана из генератора приложения. (Pull Request)Команда
rails application
была убрана без замены. (Pull Request)
Устарело
Устарел отсутствующий
config.log_level
для окружений production. (Pull Request)Устарел
rake test:all
в пользуrake test
, так как он теперь запускает все тесты в папкеtest
. (Pull Request)Устарел
rake test:all:db
в пользуrake test:db
. (Pull Request)Устарел
Rails::Rack::LogTailer
без замены. (Commit)
Значимые изменения
Представлен
web-console
в Gemfile приложения по умолчанию. (Pull Request)Добавлена опция
required
для связей в генераторе модели. (Pull Request)Представлено пространство имен
x
для определения произвольных конфигурационных опций:# config/environments/production.rb config.x.payment_processing.schedule = :daily config.x.payment_processing.retries = 3 config.x.super_debugger = true
Затем эти опции доступны в объекте configuration:
Rails.configuration.x.payment_processing.schedule # => :daily Rails.configuration.x.payment_processing.retries # => 3 Rails.configuration.x.super_debugger # => true
(Commit)
Представлен
Rails::Application.config_for
для загрузки конфигурации для текущего окружения.# config/exception_notification.yml: production: url: http://127.0.0.1:8080 namespace: my_app_production development: url: http://localhost:3001 namespace: my_app_development # config/environments/production.rb Rails.application.configure do config.middleware.use ExceptionNotifier, config_for(:exception_notification) end
Представлена опция
--skip-turbolinks
для генератора приложения, чтобы не генерировать интеграцию с turbolinks. (Commit)Представлен скрипт
bin/setup
как соглашение для автоматической настройки для быстрого развертывания вашего приложения. (Pull Request)Изменено значение по умолчанию для
config.assets.digest
наtrue
в среде development. (Pull Request)Представлен API для регистрации новых расширений для
rake notes
. (Pull Request)Представлен колбэк
after_bundle
для использования в шаблонах Rails. (Pull Request)Представлен
Rails.gem_version
как удобный метод для возвратаGem::Version.new(Rails.version)
. (Pull Request)
Action Pack
За подробностями обратитесь к Changelog.
Удалено
respond_with
и метод классаrespond_to
были убраны из Rails и перемещены в гемresponders
(версия 2.0). Добавьтеgem 'responders', '~> 2.0'
в свойGemfile
, чтобы продолжать использовать эти особенности. (Pull Request, подробнее)Убран устаревший
AbstractController::Helpers::ClassMethods::MissingHelperError
в пользуAbstractController::Helpers::MissingHelperError
. (Commit)
Устарело
Устарела опция
only_path
в хелперах*_path
. (Commit)Устарели
assert_tag
,assert_no_tag
,find_tag
иfind_all_tag
в пользуassert_select
. (Commit)Устарела поддержка опции
:to
в роутере со значением символом или строкой без символа "#":get '/posts', to: MyRackApp => (Не требуется изменения) get '/posts', to: 'post#index' => (Не требуется изменения) get '/posts', to: 'posts' => get '/posts', controller: :posts get '/posts', to: :index => get '/posts', action: :index
(Commit)
Устарела поддержка строковых ключей в хелперах URL:
# плохо root_path('controller' => 'posts', 'action' => 'index') # хорошо root_path(controller: 'posts', action: 'index')
Значимые изменения
Семейство методов
*_filter
убраны из документации. Их использование не рекомендуется в пользу семейства методов*_action
:after_filter => after_action append_after_filter => append_after_action append_around_filter => append_around_action append_before_filter => append_before_action around_filter => around_action before_filter => before_action prepend_after_filter => prepend_after_action prepend_around_filter => prepend_around_action prepend_before_filter => prepend_before_action skip_after_filter => skip_after_action skip_around_filter => skip_around_action skip_before_filter => skip_before_action skip_filter => skip_action_callback
Если ваше приложение в настоящее время зависит от этих методов, следует их заменить на методы
*_action
. Они будут объявлены устаревшими в будущем и когда-нибудь будут убраны из Rails.render nothing: true
или рендеринг телаnil
больше не добавляет одиночный пробел в тело отклика. (Pull Request)Rails теперь автоматически включает дайджест шаблона в ETag. (Pull Request)
Сегменты, передаваемые в хелперы URL, теперь автоматически экранируются. (Commit)
Представлена опция
always_permitted_parameters
для настройки, какие параметры разрешены глобально. Значение по умолчанию для этой настройки['controller', 'action']
. (Pull Request)Добавлен метод HTTP
MKCALENDAR
из RFC 4791. (Pull Request)Модификации
*_fragment.action_controller
теперь включают имена контроллера и экшна в payload. (Pull Request)Улучшена страница Routing Error с помощью нечеткого (fuzzy) соответствия для поиска маршрутов. (Pull Request)
Добавлена опция для отключения логирования ошибок CSRF. (Pull Request)
Когда сервер Rails настроен обслуживать статичные ассеты, gzip ассеты также будут обслужены, если клиент их поддерживает и предварительно генерирует файл gzip (
.gz
) на диск. По умолчанию asset pipeline генерирует файлы.gz
для всех сжимаемых ассетов. Обслуживание gzip файлов минимизирует передаваемые данные и ускоряет запрос к ассету. Всегда используйте CDN, если обслуживаете файлы ассетов на сервере Rails в production. (Pull Request)При вызове хелперов
process
в интеграционном тесте, пути необходим начальный слэш. Раньше его можно было опустить, но это был побочный продукт реализации, а не специальная особенность, т.е.:test "list all posts" do get "/posts" assert_response :success end
Action View
За подробностями обратитесь к Changelog.
Устарело
Устарели
AbstractController::Base.parent_prefixes
. ПереопределитеAbstractController::Base.local_prefixes
когда хотите изменить, где следует искать вьюхи. (Pull Request)Устарел
ActionView::Digestor#digest(name, format, finder, options = {})
. Аргументы должны быть переданы как хэш. (Pull Request)
Значимые изменения
render "foo/bar"
теперь расширяется доrender template: "foo/bar"
вместоrender file: "foo/bar"
. (Pull Request)Хелперы форм больше не генерируют элемент
<div>
с inline CSS вокруг скрытых полей. (Pull Request)Представлена специальная локальная переменная
#{partial_name}_iteration
для использования с партиалами, рендерящимися с коллекцией. Она предоставляет доступ к текущему состоянию итерации с помощью методовindex
,size
,first?
иlast?
. (Pull Request)Placeholder I18n следует тем же соглашениям, что и
label
I18n. (Pull Request)
Action Mailer
За подробностями обратитесь к Changelog.
Устарело
Устарели хелперы
*_path
в рассыльщиках. Всегда используйте вместо них хелперы*_url
. (Pull Request)Устарели
deliver
/deliver!
в пользуdeliver_now
/deliver_now!
. (Pull Request)
Значимые изменения
link_to
иurl_for
по умолчанию генерируют абсолютные URL в шаблонах, больше нет необходимости передаватьonly_path: false
. (Commit)Представлен
deliver_later
, который добавляет в очередь задание для доставки писем асинхронно. (Pull Request)Добавлена конфигурационная опция
show_previews
для включения предпросмотра писем вне окружения разработки. (Pull Request)
Active Record
За подробностями обратитесь к Changelog.
Удалено
Удален
cache_attributes
и сотоварищи. Все атрибуты кэшируются. (Pull Request)Удален устаревший метод
ActiveRecord::Base.quoted_locking_column
. (Pull Request)Удален устаревший метод
ActiveRecord::Migrator.proper_table_name
. Используйте вместо него метод экземпляраproper_table_name
наActiveRecord::Migration
. (Pull Request)Удален неиспользуемый тип
:timestamp
. Прозрачно добавлен как псевдоним к:datetime
во всех случаях. Исправлены несоответствия, когда типы столбцов используются вне Active Record, например для сериализации XML. (Pull Request)
Устарело
Устарело проглатывание ошибок в
after_commit
иafter_rollback
. (Pull Request)Устарела сломанная поддержка автоматического определения кэширующих счетчиков на связях
has_many :through
. Вместо этого следует вручную указывать кэширующий счетчик на связяхhas_many
иbelongs_to
для записей through. (Pull Request)Устарела передача объектов Active Record в
.find
или.exists?
. Вместо этого сначала вызывайтеid
на объектах. (Commit 1, 2)Устарела недоделанная поддержка интервальных значений PostgreSQL с исключенными концами (полуинтервалов). Сейчас мы переводим интервалы PostgreSQL в интервалы Ruby. Это преобразование не полностью возможно, поскольку интервалы Ruby не поддерживают исключение концов.
Текущее решение увеличения конца интервала не корректно и устарело. Для подтипов, в которых мы не знаем как увеличить (т.е. где не определен
succ
), он вызоветArgumentError
для интервалов с исключенными концами.(Commit)
Устарел вызов
DatabaseTasks.load_schema
без соединения. Вместо него используйтеDatabaseTasks.load_schema_current
. (Commit)Устарел
sanitize_sql_hash_for_conditions
без замены. Для выполнения запросов и обновлений предпочтительным API является использованиеRelation
. (Commit)Устарели
add_timestamps
иt.timestamps
без передачи опции:null
. Значение по умолчаниюnull: true
изменится в Rails 5 наnull: false
. (Pull Request)Устарел
Reflection#source_macro
без замены, так как он больше не требуется в Active Record. (Pull Request)Устарел
serialized_attributes
без замен. (Pull Request)Устарел возврат
nil
отcolumn_for_attribute
когда не существует столбец. Он будет возвращать null object в Rails 5.0 (Pull Request)Устарело использование
.joins
,.preload
и.eager_load
со связями, зависящими от состояния экземпляра (т.е. те, которые определены со скоупом, принимающим аргумент) без замены. (Commit)
Значимые изменения
SchemaDumper
используетforce: :cascade
наcreate_table
. Это позволяет перезагрузить схему с внешними ключами.Добавлена опция
:required
к одиночным связям, определяющая наличие валидации для связи. (Pull Request)ActiveRecord::Dirty
теперь обнаруживает изменения в мутируемых значениях. Сериализованные атрибуты в моделях Active Record больше не сохраняются, когда не изменились. Это также работает с другими типами, такими как строковые столбцы и json столбцы в PostgreSQL. (Pull Requests 1, 2, 3)Представлена задача Rake
db:purge
для опустошения базы данных для текущей среды. (Commit)Представлен
ActiveRecord::Base#validate!
, вызывающийActiveRecord::RecordInvalid
, если запись невалидна. (Pull Request)Представлен
#validate
в качестве псевдонима для#valid?
. (Pull Request)#touch
теперь принимает несколько атрибутов, которые будут затронуты за раз. (Pull Request)Адаптер PostgreSQL теперь поддерживает тип данных
jsonb
в PostgreSQL 9.4+. (Pull Request)Адаптеры PostgreSQL и SQLite больше не добавляют лимит по умолчанию в 255 символов для строковых столбцов. (Pull Request)
Добавлена поддержка для типа столбца
citext
в адаптере PostgreSQL. (Pull Request)Добавлена поддержка для пользовательского интервального типа в адаптере PostgreSQL. (Commit)
sqlite3:///some/path
теперь считается абсолютным системным путем/some/path
. Для относительных путей используйтеsqlite3:some/path
. (Раньшеsqlite3:///some/path
считался относительным путемsome/path
. Это поведение устарело в Rails 4.1). (Pull Request)Добавлена поддержка для долей секунд в MySQL 5.6 и выше. (Pull Request 1, 2)
Добавлен
ActiveRecord::Base#pretty_print
для красивого отображения моделей. (Pull Request)ActiveRecord::Base#reload
теперь ведет себя так же, какm = Model.find(m.id)
, что означает, что он больше не помнит дополнительные атрибуты из кастомногоSELECT
. (Pull Request)ActiveRecord::Base#reflections
теперь возвращает хэш со строковыми ключами вместо символьных ключей. (Pull Request)Метод
references
в миграциях теперь поддерживает опциюtype
для указания типа внешнего ключа (например,:uuid
). (Pull Request)
Active Model
За подробностями обратитесь к Changelog.
Удалено
- Удален устаревший
Validator#setup
без замены. (Pull Request)
Устарело
Устарел
reset_#{attribute}
в пользуrestore_#{attribute}
. (Pull Request)Устарел
ActiveModel::Dirty#reset_changes
в пользуclear_changes_information
. (Pull Request)
Значимые изменения
Представлен
#validate
в качестве псевдонима для#valid?
. (Pull Request)Представлен метод
restore_attributes
вActiveModel::Dirty
для восстановления измененных (dirty) атрибутов их предыдущими значениями. (Pull Request 1, 2)has_secure_password
по умолчанию больше не запрещает пустые пароли (т.е. пароли, содержащие только пробелы). (Pull Request)Теперь
has_secure_password
проверяет, что заданный пароль меньше 72 символов, если включены валидации. (Pull Request)
Active Support
За подробностями обратитесь к Changelog.
Удалено
Удалены устаревшие
Numeric#ago
,Numeric#until
,Numeric#since
,Numeric#from_now
. (Commit)Удалены устаревшие ограничители на основе строки для
ActiveSupport::Callbacks
. (Pull Request)
Устарело
Устарели
Kernel#silence_stderr
,Kernel#capture
иKernel#quietly
без замены. (Pull Request)Устарел
Class#superclass_delegating_accessor
, вместо него используйтеClass#class_attribute
. (Pull Request)Устарел
ActiveSupport::SafeBuffer#prepend!
так какActiveSupport::SafeBuffer#prepend
теперь выполняет ту же самую функцию. (Pull Request)
Значимые изменения
Представлена новая конфигурационная опция
active_support.test_order
для определения порядка, в котором выполняются тестовые случаи. В настоящее время эта опция по умолчанию:sorted
, но будет изменена на:random
в Rails 5.0. (Commit)Object#try
иObject#try!
теперь могут использоваться без явного получателя в блоке. (Commit, Pull Request)Тестовый хелпер
travel_to
теперь обрезает компонентusec
до 0. (Commit)Представлен
Object#itself
как идентифицирующая функция. (Commit 1, 2)Теперь
Object#with_options
может использоваться без явного получателя в блоке. (Pull Request)Представлен
String#truncate_words
для обрезания строки по количеству слов. (Pull Request)Добавлены
Hash#transform_values
иHash#transform_values!
для упрощения обычной практики, когда значения хэша должны измениться, но ключи остаются прежними. (Pull Request)Теперь словообразующий хелпер
humanize
отбрасывает любые начальные знаки подчеркивания. (Commit)Представлен
Concern#class_methods
как альтернативаmodule ClassMethods
, а такжеKernel#concern
для избегания шаблонногоmodule Foo; extend ActiveSupport::Concern; end
. (Commit)Новое руководство про автозагрузку и перезагрузку констант.
Благодарности
Взгляните на полный список контрибьюторов Rails, на людей, которые потратили много часов, сделав Rails стабильнее и надёжнее. Спасибо им всем.