Ключевые новинки в Rails 4.2:
Эти заметки о релизе покрывают только основные изменения. Чтобы узнать о других обновлениях, различных исправлениях программных ошибок и изменениях, обратитесь к логам изменений или к списку коммитов в главном репозитории Rails на GitHub.
Прежде чем апгрейднуть существующее приложение, было бы хорошо иметь перед этим покрытие тестами. Также, до попытки обновиться до Rails 4.2, необходимо сначала произвести апгрейд до Rails 4.1 и убедиться, что приложение все еще выполняется так, как нужно. Список вещей, которые нужно выполнить для апгрейда доступен в руководстве Апгрейд Ruby on Rails.
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 — это набор улучшений производительности в 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)
Важно подчеркнуть то, что, как подчеркивают вышеприведенные примеры, подготовленные выражения не кэшируют значения, переданные в вызов метода, они только являются местозаполнителями для них.
Кэширование не используется в следующих сценариях:
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
, были изменены:
:reserved
был убран.
:request_entity_too_large
был переименован в :payload_too_large
.
:request_uri_too_long
был переименован в :uri_too_long
.
:requested_range_not_satisfiable
был переименован в :range_not_satisfiable
.
Имейте в виду, что если вызывается render
с неизвестным символом, статус отклика будет по умолчанию 500.
Санитайзер 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.
За подробностями обратитесь к 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)
За подробностями обратитесь к 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
За подробностями обратитесь к 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>
со встроенным CSS вокруг скрытых полей.
(Pull Request)
Представлена специальная локальная переменная #{partial_name}_iteration
для использования с партиалами, рендерящимися с коллекцией. Она предоставляет доступ к текущему состоянию итерации с помощью методов index
, size
, first?
и last?
.
(Pull Request)
Местозаполнитель I18n следует тем же соглашениям, что и label
I18n.
(Pull Request)
За подробностями обратитесь к 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)
За подробностями обратитесь к 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)
За подробностями обратитесь к 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)
За подробностями обратитесь к 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 стабильнее и надёжнее. Спасибо им всем.