Статьи

Копаем в Rails 4

Рельсы 4 стремительно приближаются . В этой статье давайте рассмотрим некоторые из новых функций, которые он предлагает, а также изменения, которые могут повлиять на ваши текущие приложения.


Дайджесты кэша — это решение Rails 4 для отслеживания изменений в агрессивно кэшированных шаблонах.

В Rails 4 есть несколько конфигурационных и структурных изменений.

Rails 4 будет поддерживать только Ruby 1.9.3+. Будьте готовы к обновлению, если еще не сделали этого.

Rails 4 будет поточно-ориентированным по умолчанию, устраняя издержки и улучшая производительность на многопоточных серверах, таких как thin и puma . Вы должны убедиться, что ваше приложение (и его зависимости) являются поточно-ориентированными, что обычно означает избегание глобального состояния (например, класса или глобальных переменных).

Аарон Паттерсон писал и говорил на эту тему. Определенно проверьте это!

Rails 3 придерживался идеи использования гемов для добавления пользовательских функций в Rails и не одобрял использование плагинов. Rails 4 завершает этот переход, полностью удаляя каталог vendor/plugins .

Схема именования каталогов по умолчанию более понятна, чем в Rails 3.

Теперь будут созданы следующие каталоги: test/models , test/helpers , test/controllers , test/mailers и test/integration .

Каталог script был удален в пользу нового каталога bin . Именно здесь будут жить исполняемые файлы вашего приложения и запускать rake rails:update:bin поместит binstubs bundle , rake и rails каталог bin вашего приложения.

Это изменение может быть полезно при разработке, особенно на машине с несколькими версиями Ruby и гемами. Вы можете использовать bin/rails вместо bundle exec rails чтобы убедиться, что вы запускаете свои исполняемые файлы в правильной среде.


Rails 4 решает проблему массового назначения с новым гемом Strong Parameters . Приложение Rails 3 может иметь действие create подобное следующему примеру:

1
2
3
4
5
6
class UsersController < ApplicationController
  def create
    @user = User.create(params[:user])
    # … check validity, redirect, etc.
  end
end

Вы можете защитить от неожиданного ввода с помощью объявлений в модели:

1
2
3
4
class User < ActiveRecord::Base
  # Only allow the following attributes to be mass-assigned
  attr_accessible :name, :email
end

Использование Strong Parameters в Rails 4 перемещает пользовательский ввод в контроллер:

01
02
03
04
05
06
07
08
09
10
class UsersController < ApplicationController
  def create
    @user = User.create(user_params)
    # … check validity, redirect, etc.
  end
 
  def user_params
    params.require(:user).permit(:name, :email)
  end
end

Как видите, хэш params в вашем контроллере не является обычным хешем. На самом деле это экземпляр ActionController::Parameters , который предоставляет методы require и ActionController::Parameters .

Метод require обеспечивает доступность указанного ключа в хэше params и вызывает исключение ActionController::ParameterMissing если ключ не существует.

Метод permit защищает вас от неожиданного массового назначения.

Вызов User.create(params[:user]) вызывает исключение User.create(params.require(:user).permit(:name, :email)) ActiveModel::ForbiddenAttributesError , но использование User.create(params.require(:user).permit(:name, :email)) заставляет его работать без жалоб.

Функциональность массового назначения в Rails 3 не только отключена в Rails 4, но и была извлечена в гем , на случай, если вам потребуется эта функциональность.


По умолчанию Rails 4 будет поточно-ориентированным, устраняя издержки и улучшая производительность.

Спорные новая функция в Rails 4 является Turbolinks , JavaScript плагин разработан , чтобы сделать приложение навигации быстрее в браузере.

В браузерах с поддержкой pushState нажатие на ссылку вызывает плагин Turbolinks . Он делает запрос Ajax, обновляет URL с помощью pushState (чтобы ваша кнопка назад pushState ) и использует JavaScript для обновления <title> и <body> в DOM. Повышение скорости происходит из-за того, что нет необходимости загружать и обрабатывать ресурсы JavaScript и CSS.

Turbolinks изящно ухудшается для браузеров, которые не поддерживают pushState . В этих ситуациях ссылки на страницы ведут себя как обычно, вызывая полное обновление страницы.

В приложениях принято ждать полной загрузки страницы перед выполнением любого JavaScript. Например:

1
2
3
$(document).ready(/* some function to run */) {
  // or event just $(/* some function to run */)
}

С Turbolinks события загрузки страницы не будут срабатывать, когда пользователи переходят от «страницы» к «странице», потому что DOM фактически никогда не перезагружается. Поэтому библиотека добавляет новые события, которые вы можете прослушивать, чтобы выполнить любые последующие инициализации, которые могут понадобиться вашему приложению:

  • page:fetch — начало загрузки страницы с сервера
  • page:change — страница была загружена
  • page:load — страница была загружена с сервера
  • page:restore — страница была загружена из кеша

Событие page:change всегда срабатывает, когда Turbolinks загружает страницу, за которой следует page:load или page:restore , в зависимости от того, была ли загрузка получена с сервера или из кэша.

Скоро появится Rails 4, и он внес множество изменений в структуру.

У Turbolinks есть несколько проблем, которые вам, возможно, придется решить:

  • Утечки памяти : Turbolinks не очищает и не перезагружает ваш JavaScript при изменении страницы. Вы можете увидеть последствия утечек памяти в своих приложениях, особенно если вы используете много JavaScript.
  • Привязки к событиям : вы должны принять во внимание старые браузеры. Убедитесь, что вы слушаете события page:* , а также DOMContentLoaded .
  • Клиентские фреймворки : Turbolinks могут плохо работать с другими клиентскими фреймворками, такими как Backbone, Angular, Knockout, Ember и т. Д.

Вы можете отказаться от Turbolinks:

  1. удаление turbolinks из вашего Gemfile, и
  2. удаление строки //= require turbolinks из application.js

Rails 4 предлагает переработанную стратегию кэширования. Во-первых, кэширование действий и страниц, как вы, возможно, знаете из предыдущих версий Rails, было удалено и извлечено в gems: action и page соответственно.

Новый ребенок на блоке — русская кукла, или кэширование вложенных фрагментов. Самый простой способ понять эту систему — взглянуть на некоторый код. Предположим, что у вас есть приложение для управления проектами. У вас могут быть следующие модели:

1
2
3
4
5
6
7
class Milestone < ActiveRecord::Base
  has_many :todos
end
 
class Todo < ActiveRecord::Base
  belongs_to :milestone, :touch => true
end

Опция :touch требуется для правильной работы стратегии кэширования. Если задача добавлена ​​к вехе, нам нужно разбить кеш на вехе, чтобы избежать обслуживания устаревших представлений.

Теперь у нас есть мелкозернистые кэши в наших представлениях. Рассмотрим этот файл в качестве примера ( app/views/milestones/show.html.erb ):

1
2
3
4
5
6
7
8
<% cache @milestone do %>
  <h1><%= @milestone.name %></h1>
  <div class=»description»><%= @milestone.description %></div>
 
  <ul class=»todos»>
    <%= render @milestone.todos %>
  </ul>
<% end %>

И в app/views/todos/_todo.html.erb :

1
2
3
4
5
6
<% cache todo do %>
  <li class=»todo»>
    <%= todo.description %>
    <span class=»status»><%= todo.status %>
  </li>
<% end %>

Теперь предположим, что у вас есть веха с десятью задачами. Редактирование только одной задачи приводит к разрыву кэша вехи, но при генерации HTML из кэша могут быть получены все части, кроме одной, чтобы сократить время рендеринга.

PATCH теперь новый HTTP-глагол для обновления ресурсов.

Вы тратите время на пространство, так как это приводит к большим потерям в вашем кеше. Но, как указывает DHH , хранилища кеша, такие как Memcached, просто отбрасывают старые данные, чтобы освободить место для новых данных. Так что это не проблема в большинстве случаев.

Дайджесты кэша — это решение Rails 4 для отслеживания изменений в агрессивно кэшированных шаблонах. Rails 4 отслеживает шаблоны и их зависимости, а также суффиксирует ключи кеша фрагмента с дайджестом шаблона MD5 (и его зависимостями). Когда вы редактируете один из ваших шаблонов, его ключ кеша получает обновление, и вам не придется вручную создавать версии шаблонов.

Для получения дополнительной информации (и для использования в Rails 3), ознакомьтесь с README для гема дайджестов кэша .


Новый ActionController::Live предоставляет возможность потоковой передачи данных клиентам. Просто включите модуль в контроллер, чтобы приложение могло отправлять произвольные потоковые данные. Вам придется использовать многопоточный сервер, например thin и puma , для потоковой передачи данных; действия от потоковых контроллеров выполняются в отдельном потоке.

Вот пример из документации по Rails 4:

01
02
03
04
05
06
07
08
09
10
11
12
class MyController < ActionController::Base
  include ActionController::Live
 
  def stream
    response.headers[‘Content-Type’] = ‘text/event-stream’
    100.times {
      response.stream.write «hello world\n»
        sleep 1
    }
    response.stream.close
  end
end

Как отмечают документы , нужно помнить о трех вещах:

  • Вы должны записать любые заголовки, прежде чем вызывать write или close в потоке ответов.
  • Вы должны вызвать close в потоке ответов, когда закончите запись данных.
  • Убедитесь, что ваши действия являются потокобезопасными, так как они будут выполняться в отдельном потоке.

Мы поговорили о «заголовочных» функциях в Rails 4. Но этот выпуск большой и включает в себя ряд небольших изменений, о которых нужно знать.

Как описано в блоге Rails , PATCH теперь является HTTP-глаголом для обновления ресурсов.

Это изменение, как правило, будет прозрачным для разработчиков, поскольку запросы PUT будут по-прежнему направляться к действию update для маршрутов в стиле RESTful.

Но это изменение, о котором вы должны знать; PUT маршрутизация может измениться в будущем.

Эта небольшая функция может помочь очистить некоторый код. Вы можете зарегистрировать свои собственные типы флэш-памяти для использования в вызовах redirect_to и в шаблонах. Например:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
# app/controllers/application_controller.rb
class ApplicationController
  add_flash_types :error, :catastrophe
end
 
# app/controllers/things_controller.rb
class ThingsController < ApplicationController
  def create
    # … create a thing
  rescue Error => e
    redirect_to some_path, :error => e.message
  rescue Catastrophe => e
    redirect_to another_path, :catastrophe => e.message
  end
end
 
# app/views/layouts/application.html.erb
<div class=»error»><%= error %></div>
<div class=»catastrophe»><%= catastrophe %></div>

В Rails 4 устарели хэши опций поиска в старом стиле, а также все методы динамического поиска (за исключением find_by_... и find_by_... ). Вместо этого вы будете использовать where :

  • find_all_by_... можно переписать с помощью where(...) .
  • find_last_by_... можно переписать, используя where(...).last .
  • scoped_by_... можно переписать с помощью where(...) .
  • find_or_initialize_by_... можно переписать с помощью where(...).first_or_initialize .
  • find_or_create_by_... может быть переписан с использованием find_or_create_by(...) или where(...).first_or_create .
  • find_or_create_by_...! может быть переписан с помощью find_or_create_by!(...) или where(...).first_or_create! ,

Устаревший драгоценный камень поиска будет включен в качестве зависимости в 4.0. и удалено в 4.1. Драгоценный камень, однако, будет вокруг и поддерживается до 5.0.

Проблемы маршрутизации — это попытка высушить ваш config/routes.rb Основная идея состоит в том, чтобы определить общие подресурсы (например, комментарии) как проблемы и включить их в другие ресурсы / маршруты. Вот очевидный пример:

01
02
03
04
05
06
07
08
09
10
concern :commentable do
  resources :comments
end
 
concern :remarkable do
  resources :remarks
end
 
resources :posts, :concerns => :commentable
resources :articles, :concerns => [:commentable, :remarkable] # can include several

Вышесказанное эквивалентно следующему коду Rails 3:

1
2
3
4
5
6
7
8
resources :posts do
  resources :comments
end
 
resources :articles do
  resources :comments
  resources :remarks
end

Лично я не уверен, что это добавляет много ценности; возможно, это имеет смысл для больших приложений с сотнями маршрутов.

Обратные вызовы действий в контроллерах были переименованы из *_filter в *_action . Например:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
class UsersController < ApplicationController
  before_action :set_user, :except => [:index, :new, :create}
  before_action :require_the_president, :only => [:fire_the_missiles]
 
  private
 
  def set_user
    @user = somehow_find_and_set_the_user(params[:id])
  end
 
  def require_the_president
    @user.is_the_president?
  end
end

Старые *_filter вызовы *_filter прежнему работают и не являются устаревшими; так что вы можете использовать их, если хотите. DHH причина изменения была:

«Чтобы избежать ошибочного представления о том, что эти обратные вызовы подходят только для преобразования или остановки ответа. В новом стиле более привлекательным является их использование по назначению, например установка общих иваров для представлений».


Скоро появится Rails 4, принесший с собой множество изменений. Я надеюсь, что эта статья дала вам представление о том, чего ожидать, и, возможно, отправную точку для изучения того, что может предложить эта новая версия.

Если вы действительно хотите углубиться в глубокий конец, ознакомьтесь с нашим курсом Tuts + Premium по Rails 4 !