Заметки о релизе 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 следует тем же соглашениям, что и
labelI18n. (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 стабильнее и надёжнее. Спасибо им всем.