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

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

  • Ruby 2.0 предпочтителен; 1.9.3+ требуется
  • Строгие параметры (Strong Parameters)
  • Turbolinks
  • Кэширование "матрешкой" (Russian Doll Caching)

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

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

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

2. Создание приложения Rails 4.0

# Необходим установленный RubyGem 'rails'
$ rails new myapp
$ cd myapp

2.1. Сторонние гемы

Сейчас Rails использует Gemfile в корне приложения, чтобы определить гемы, требуемые для запуска вашего приложения. Этот Gemfile обрабатывается гемом Bundler, который затем устанавливает все зависимости. Он может даже установить все зависимости локально в ваше приложение, и оно не будет зависеть от системных гемов.

Подробнее: - домашняя страница Bundler

2.2. Живите на грани

Bundler и Gemfile замораживает ваше приложение Rails с помощью новой отдельной команды bundle. Если хотите установить напрямую из репозитория Git, передайте флажок --edge:

$ rails new myapp --edge

Если имеется локальная копия репозитория Rails, и необходимо сгенерировать приложение используя ее, передайте флажок --dev:

$ ruby /path/to/rails/railties/bin/rails new myapp --dev

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

Rails 4.0

3.1. Апгрейд

  • Ruby 1.9.3 (коммит) - Предпочтителен Ruby 2.0; требуется 1.9.3+
  • Новая политика устареваний - Устаревшие особенности показывают предупреждения в Rails 4.0, и будут убраны в Rails 4.1.
  • Кэширование страниц и экшнов ActionPack (коммит) - Кэширование страниц и экшнов было извлечено в отдельный гем. Кэширование страниц и экшнов требовало слишком много человеческого вмешательства (вручную прекращать кэш, когда обновляются лежащие в основе объекты модели). Вместо этого используйте кэширование по принципу "русской матрешки" (Russian doll caching).
  • Обсерверы ActiveRecord (коммит) - Обсерверы извлечены в отдельный гем. Обсерверы требовались только для кэширования страниц и экшнов и могли привести к спагетти-коду.
  • Хранилище сессии ActiveRecord (коммит) - Хранилище сессии ActiveRecord извлечено в отдельный гем. Хранение сессий в SQL затратное. Используйте вместо него сессии куки, сессии memcache или произвольные хранилища сессии.
  • Защита от массового назначения ActiveModel (коммит) - Защита от массового назначения Rails 3 устарела. Вместо нее используйте строгие параметры (strong parameters).
  • ActiveResource (коммит) - ActiveResource извлечен в отдельный гем. ActiveResource не был широко используемым.
  • убраны vendor/plugins (коммит) - Для управления установленными гемами используйте Gemfile.

3.2. ActionPack

  • Strong parameters (коммит) - Позволяет обновлять объекты модели только разрешенными параметрами (params.permit(:title, :text)).
  • Routing concerns (коммит) - В маршрутном DSL, выделяет общие подмаршруты (comments из /posts/1/comments and /videos/1/comments).
  • ActionController::Live (коммит) - Потоковый JSON с помощью response.stream.
  • Декларативные ETags (коммит) - Добавляет на уровне контроллера дополнения к etag, которые будут частью вычисления etag.
  • Кэширование Russian doll (коммит) - Кэширует вложенные фрагменты вью. Каждый фрагмент прекращается на основе набора зависимостей (ключа кэширования). Ключ кэширования - это обычно версия шаблона и объект модели.
  • Turbolinks (коммит) - Обслуживает только первую страницу HTML. Когда пользователь переходит на следующую страницу, использует pushState для обновления URL и использует AJAX для обновления title и body.
  • Извлечение ActionView из ActionController (коммит) - ActionView был отделен от ActionPack, и будет вынесен в отдельный гем в Rails 4.1.
  • Независимость от ActiveModel (коммит) - ActionPack больше не зависит от ActiveModel.

3.3. Основное

  • ActiveModel::Model (коммит) - ActiveModel::Model - это миксин, чтобы обычные объекты Ruby могли работать с ActionPack "из коробки" (например, form_for).
  • Новый API скоупов (коммит) - Скоупы должны быть всегда вызываемыми.
  • Выгрузка кэша схемы (коммит) - Чтобы улучшить время загрузки Rails, вместо загрузки схемы непосредственно из базы данных, загружает схему из файла выгрузки.
  • Поддержка указания уровня изоляции транзакции (коммит) - Выбирайте, что более важно - повторяемые чтения или улучшенное быстродействие (менее блокирующее).
  • Dalli (коммит) - Используется клиент Dalli в качестве хранилища сессии в memcache.
  • start & finish для уведомлений (коммит) - Инструменты Active Support сообщают подписчикам о начале и завершении уведомлений.
  • Тредобезопасность по умолчанию (коммит) - Rails может быть запущен на тредовых серверах приложений без дополнительных настроек. Заметка: Проверьте, что используемые вами гемы тредобезопасны.

Убедитесь, что используемые вами гемы тредобезопасны.

  • Метод PATCH (коммит) - В Rails PATCH заменил PUT. PATCH используется для частичного обновления ресурсов.

3.4. Безопасность

  • match не соответствует всем методам (коммит) - В маршрутном DSL, match требует указания метода или методов HTTP.
  • Сущности html экранируются по умолчанию (коммит) - Строки, рендерящиеся в erb, экранируются, если не обернуты в raw, или вызван html_safe.
  • Новые заголовки безопасности (коммит) - Rails посылает следующие заголовки с каждым запросом HTTP: X-Frame-Options (предотвращает кликджекинг, запрещая браузеру встраивать страницу в фрейм), X-XSS-Protection (говорит браузеру прерывать инъекцию скрипта) и X-Content-Type-Options (предотвращает открытие браузером jpeg как exe).

4. Извлечение особенностей в гемы

В Rails 4.0 некоторые особенности были извлечены в гемы. Можно просто добавить извлеченный гем в свой Gemfile, чтобы вернуть функциональность.

5. Документация

  • Руководства были переписаны на GitHub Flavored Markdown.

  • Руководства имеют адаптивный дизайн.

6. Railties

Обратитесь к Changelog за полными изменениями.

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

  • Новые места расположения для тестов test/models, test/helpers, test/controllers и test/mailers. Также добавлены соответствующие задачи rake. (Pull Request)

  • Исполняемые файлы приложения теперь находятся в директории bin/. Запустите rake rails:update:bin чтобы получить bin/bundle, bin/rails и bin/rake.

  • Тредобезопасность включена по умолчанию

  • Была убрана возможность использования произвольного билдера, передав --builder (или -b) в rails new. Вместо нее рассмотрите шаблоны приложения. (Pull Request)

6.2. Устаревания

  • config.threadsafe! устарело в пользу config.eager_load, которая предоставляет более тонкую настройку того, что будет лениво загружаться.

  • Rails::Plugin больше нет. Вместо добавления плагинов в vendor/plugins, используйте гемы, или bundler с путем, или зависимости git.

7. Action Mailer

Обратитесь к Changelog за полными изменениями.

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

7.2. Устаревания

8. Active Model

Обратитесь к Changelog за полными изменениями.

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

  • Добавлен ActiveModel::ForbiddenAttributesProtection, простой модуль для защиты атрибутов от массового назначения, когда передаются неразрешенные атрибуты.

  • Добавлен ActiveModel::Model, примесь, чтобы объекты Ruby могли работать с Action Pack "из коробки".

8.2. Устаревания

9. Active Support

Обратитесь к Changelog за полными изменениями.

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

  • Заменен устаревший гем memcache-client на dalli в ActiveSupport::Cache::MemCacheStore.

  • Оптимизирован ActiveSupport::Cache::Entry для уменьшения расхода памяти и процессора.

  • Словоизменения теперь могут быть определены для локали. singularize и pluralize принимают локаль как дополнительный аргумент.

  • Object#try теперь будет возвращать nil вместо вызова NoMethodError, если вызывающий объект не реализует этот метод, но все еще можно получить старое поведение, используя новый метод Object#try!.

  • String#to_date теперь вызывает ArgumentError: invalid date вместо NoMethodError: undefined method 'div' for nil:NilClass при получения неверной даты. Это то же самое, что и Date.parse, и он принимает больше неправильных дат, чем 3.x, такие как:

    # ActiveSupport 3.x
    "asdf".to_date # => NoMethodError: undefined method `div' for nil:NilClass
    "333".to_date # => NoMethodError: undefined method `div' for nil:NilClass
    
    # ActiveSupport 4
    "asdf".to_date # => ArgumentError: invalid date
    "333".to_date # => Fri, 29 Nov 2013
    

9.2. Устаревания

  • Устарел метод ActiveSupport::TestCase#pending, используйте вместо него skip из minitest.

  • ActiveSupport::Benchmarkable#silence устарел из-за недостатков в тредобезопасности. Он будет убран без замен в Rails 4.1.

  • Устарел ActiveSupport::JSON::Variable. Определяйте собственные методы #as_json и #encode_json для собственных строковых литер JSON.

  • Устарел метод совместимости Module#local_constant_names, используйте вместо него Module#local_constants (который возвращает символы).

  • Устарел ActiveSupport::BufferedLogger. Используйте ActiveSupport::Logger или logger из стандартной библиотеки Ruby.

  • Устарели assert_present и assert_blank в пользу assert object.blank? и assert object.present?

10. Action Pack

Обратитесь к Changelog за полными изменениями.

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

  • Изменена таблица стилей для страниц исключений для режима development. Также дополнительно отображается строчка кода и фрагмент, который вызвал исключение на всех страницах исключений.

10.2. Устаревания

11. Active Record

Обратитесь к Changelog за полными изменениями.

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

  • Улучшены способы написания миграций change, что делает старые методы up & down больше не нужными.

    • Методы drop_table и remove_column теперь обратимые, если дана вся необходимая информация. Метод remove_column принимает несколько имен столбцов; вместо использования remove_columns (который необратимый). Метод change_table также обратимый, если его блок не вызывает remove, change или change_default
    • Новый метод reversible делает возможным определить код для исполнения при выполнении или откате миграции. Смотрите руководство Миграции Active Record
    • Новый метод revert обратит всю миграцию или предоставленный блок. Если миграция откатывается, данная миграция / блок выполняется обычно. Смотрите руководство Миграции Active Record
  • Добавлена поддержка массивов PostgreSQL. Для создания столбца array может быть использован любой тип данных, с полной поддержкой миграций и выгрузкой схемы.

  • Добавлен Relation#load для явной загрузки записи и возврата self.

  • Model.all теперь возвращает ActiveRecord::Relation, а не массив с записями. Используйте Relation#to_a, если вы действительно хотите массив. В некоторых особенных случаях это может вызвать повреждения при апгрейде.

  • Добавлен ActiveRecord::Migration.check_pending!, вызывающий ошибку, если миграции ожидают выполнения.

  • Добавлена поддержка произвольного кодирования для ActiveRecord::Store. Теперь можно установить собственное кодирование следующим образом:

    store :settings, accessors: [ :color, :homepage ], coder: JSON
    
  • Соединения mysql и mysql2 будут по умолчанию устанавливать SQL_MODE=STRICT_ALL_TABLES, чтобы избежать тихих потерь данных. Это может быть отключено, определив strict: false в database.yml.

  • Убрана IdentityMap.

  • Убрано автоматическое выполнение запросов EXPLAIN. Опция active_record.auto_explain_threshold_in_seconds больше не используется и должна быть убрана.

  • Добавлены ActiveRecord::NullRelation и ActiveRecord::Relation#none, реализующие паттерн нулевого объекта для класса Relation.

  • Добавлен миграционный хелпер create_join_table для создания соединительных таблиц HABTM.

  • Могут быть созданы записи PostgreSQL hstore.

11.2. Устаревания

  • Устарел старый API поиска, основанный на хэше. Это означает, что методы, ранее принимающие "опции поиска", больше так не делают.

  • Устарели все динамические методы, кроме find_by_... и find_by_...! устарели. Вот как можно переписать код:

    • find_all_by_... может быть переписан с использованием where(...).
    • find_last_by_... может быть переписан с использованием where(...).last.
    • scoped_by_... может быть переписан с использованием where(...).
    • find_or_initialize_by_... может быть переписан с использованием find_or_initialize_by(...).
    • find_or_create_by_... может быть переписан с использованием find_or_create_by(...).
    • find_or_create_by_...! может быть переписан с использованием find_or_create_by!(...).

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

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