はじめに
今年のバージョン5.0のリリースに引き続き、来年にはRuby on Railsのバージョン5.1がリリースされようとしています。
Rails 5.0は、APIモードやAction Cableなど、APIやWebSocket周りの新機能を中心としたリリースでしたが、Rails 5.1は、React / webpack / Yarn(npmパッケージ)のサポートなど、フロントエンド周りの新機能を中心としたリリースとなりそうです。
本記事では、昨年のRails 5.0の記事に引き続いて、GitHubのRailsプロジェクトのIssuesやPull Requestsの履歴をもとに、Rails 5.1の主要な新機能・変更点の紹介を行います。
新機能
Reactとwebpackのサポート
Webpackerというパッケージを使用することで、JavaScriptファイルの依存関係の処理やnpmパッケージの管理などをwebpack経由で行えるようになりました。
Webpacker自体は既存のアセットパイプラインと共存し、比較的規模の大きいシングルページアプリケーションのようなJavaScriptの管理を行います。
(Webpackerが管理するJavaScriptのパスは、app/javascript/packs/
になっています。)
webpackのサポートを有効にするには、rails new
コマンドのオプションで--webpacker
を使用するか、Gemfileのgem 'webpacker'
の部分を有効にして、bin/rails webpacker:install
を実行します。
標準でReactもサポートされており、新しいアプリケーションの場合はrails new myapp --webpack=react
を、既存のアプリケーションの場合は、rails webpacker:install:react
をそれぞれ実行することですぐに利用することができます。
Yarnとnpmパッケージのサポート
rails new
コマンドを実行した際にデフォルトでYarnとnpmパッケージのサポートを有効にするようにしました。これによって、vendor/package.json
がアプリケーションに追加され、vendor/node_modules
がアセットパイプラインのパスに追加されます。
(node_modules
は上記のWebpackerが管理するJavaScriptとは別のパスに存在します。)
rails new
コマンド実行時にYarnのサポートを無効にするには、--skip-yarn
を指定します。
Sprockets 4
アセットのコンパイルを行うSprocketsがバージョン3から4に上がり、以下のような新機能が追加されました。
- ソースマップ
- マニフェストファイル
- BabelによるES6 (ECMAScript6/ES2015)のサポート
- npm管理下のアセットのサポート
詳細に関しては、以下を参照してください。
機能追加
form_with
これまで似たような使い方がされてきたform_tag
とform_for
の代わりにform_with
を使用することができるようになりました。
form_tag
とform_for
は受け取るパラメータやフォーム内部のフィールド用のタグなどが異なっていましたが、form_with
によって共通の方法でフォームを作成することができるようになります。
(Rails 6ではform_with
に完全に統合され、form_tag
とform_for
は非推奨になる可能性があります。)
また、form_with
では、以下のような変更が加えられています。
- 標準では出力されるHTMLタグにDOMのid属性やclass属性をつけないようにしました。これは特にid属性の重複をなくすためで、必要な場合は簡単に追加することもできます。
- id属性やclass属性を追加する際に、オプションの
html: {}
の値に入れる必要がなくなりました。これは、id
やclass
といった名前が他のキーの名前とほぼ重複しないためです。 - モデルの属性以外のフィールドを許可するようにしました。これによって、登録確認のチェックボックスなど、モデルに含まれないフィールドをフォームに入れるのが容易になりました。
-
remote: true
オプションがデフォルトになりました。フォーム送信後は、全く新しいページに遷移するのではなく、Turbolinks.visit()
か、サーバー側で生成されたレスポンス(のJavaScript)を使用します。
例)
-
form_with
でurl
を指定した場合
<%= form_with url: posts_path do |form| %>
<%= form.text_field :title %>
<% end %>
↓
<form action="/posts" method="post" data-remote="true">
<input type="text" name="title">
</form>
-
form_with
でmodel
を指定した場合
<%= form_with model: Post.new do |form| %>
<%= form.text_field :title %>
<% end %>
↓
<form action="/posts" method="post" data-remote="true">
<input type="text" name="post[title]">
</form>
- Provide form_with as a new alternative to form_for/form_tag
- Add form_with to unify form_tag/form_for.
tagヘルパの記法改善
ActionView::Helpers::TagHelper
で提供されている#tag
と#content_tag
のパラメータを減らし、HTML5をサポートするようにしました。
(下の例に示すように、これまで、上記のメソッドは多くのパラメータを渡す必要があり、デフォルトとしてXTHMLを想定していたため冗長な記述が必要でした。)
これにより、新しい記法では、より短くシンプルにヘルパなどでタグを記述することができるようになります。
古い記法
tag(:br, nil, true)
content_tag(:div, content_tag(:p, "Hello world!"), class: "strong")
<%= content_tag :div, class: "strong" do -%>
Hello world!
<% end -%>
新しい記法
tag.br
tag.div tag.p("Hello world!"), class: "strong"
<%= tag.div class: "strong" do %>
Hello world!
<% end %>
ActiveJob::Baseにretry_on / discard_onを追加
Active Jobで例外が発生した場合のジョブの再試行と破棄の動作を指定できるようになりました。
再試行 (retry_on
)
例外をキャッチして、ジョブの再試行を指定した試行回数分だけ実行します。試行回数を超えた場合は、例外はキャッチされません。
再試行が失敗した場合は、ブロックを渡して独自の処理を行うこともできます。
オプション
-
wait
: 再試行の間隔を秒単位で指定することができます。(デフォルト: 3秒) -
exponentially_longer
: 再試行の間隔に指数アルゴリズムを使用します。 (回数**4 + 2,となり、3秒後、18秒後、83秒後、…に再試行を行います。) -
attempts
: 指定した回数だけ再試行を行います。(デフォルト: 5回) -
queue
: 再試行を指定した別のキューで行います。 -
prioriry
: 再試行を別の優先度で行います。
例)
class RemoteServiceJob < ActiveJob::Base
retry_on CustomAppException
retry_on ActiveRecord::StatementInvalid, wait: 5.seconds, attempts: 3
retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10
..
end
破棄
例外が発生した場合は再試行を行わずにジョブを破棄します。これは対象となるモデルのデータが存在しない場合などで使用することができます。
例)
class SearchIndexingJob < ActiveJob::Base
discard_on ActiveJob::DeserializationError
..
end
変更点
jQuery依存の廃止
これまで使用されていたRailsのJavaScirptのjquery-ujsがjQueryではなく素のJavaScriptで書き直されてrails-ujsとなりました。
PostgreSQLとMySQLのプライマリキーがBIGINTに
PostgreSQLとMySQLの両方でデフォルトのプライマリキーがIntegerからBIGINTになりました。(SQLiteはBIGINTのプライマリキーをサポートしていないので、Integerのままです。)
既存のテーブルはIntegerのままで、新しいテーブルでBIGINTのプライマリキーが有効になります。
ActiveRecord::NotNullViolation
NOT NULL制約の為にモデルの保存に失敗した場合は、ActiveRecord::StatementInvalidの代わりにActiveRecord::NotNullViolationを例外として発生するようにしました。
ActiveRecord::DeadlockError
トランザクション処理でシリアライズに失敗した場合や、デッドロックが検出された場合に、RDBMSのエラーコードを元に、ActiveRecord::DeadlockErrorを例外として発生するようにしました。
- Provide unified ActiveRecord::DeadlockError
- Introduce AR::TransactionSerializationError for transaction serialization failures or deadlocks
- Introduce new ActiveRecord transaction error classes
Time形式のカラムがタイムゾーンを考慮するように
マイグレーションで:datetime
を指定したカラムだけでなく、:time
を指定したカラムも、標準でタイムゾーンを考慮して(具体的には、Time.zone
として)処理が行われることになりました。
以前の挙動に戻すには以下のように設定を行う必要があります。
config/application.rb
config.active_record.time_zone_aware_types = [:datetime]
Active Record (Active Model)のコールバックの停止条件の変更
これまで、Active RecordやActive Modelで、before_save
/ before_validation
のコールバックのメソッドの返り値がfalse
の場合は実行を停止してましたが、この挙動が変更になり、Rails 5.0で導入されたthrow :abort
の呼び出しによってのみ停止するようになりました。
(特にRails 4からアプリケーションをアップグレードした場合はfalse
で停止を行っていないかチェックが必要です。)
廃止
ActionController::TestCaseをgemとして分離
Rails 5.0ではActionDispatch::IntegrationTestをActionController::TestCaseの代わりに標準で使用するようになっており、ActionController::TestCaseは非推奨になっていました。
Rails 5.1ではActionController::TestCaseはgemとしてRailsとは別のリポジトリに切り離されて、標準では利用できなくなります。
コントローラのコールバックの名称をaction
を用いたものに統一
before_filter
/ after_filter
などのfilter
を用いた名称が廃止され、before_action
/ after_action
などaction
を用いた名称に統一されます。
redirect_to :back
の廃止
コントローラ内で以前のアクセスしたURLに戻る際に用いられてきた、redirect_to :back
のメソッド呼び出しが廃止され、代わりにredirect_back(fallback_location: fallback_location)
を使うようにする必要があります。ここで、fallback_location
としてはリクエストにHTTPリファラの情報がない場合に戻る場所(URL)を指定します。
render :nothing
の廃止
コントローラ内でステータスコードのみを返す場合に利用されていたrender :nothing
のメソッド呼び出しが廃止されました。
Rails 5.1以降では、単純にステータスコードを返す場合、head :created
のように、head
メソッドを使用する必要があります。
params
(コントローラ内のパラメータ)とハッシュの比較ができないように
Rails 5でActionController::ParametersがHashから継承しなくなったのに伴い、Rails 5.1ではparamsとハッシュの比較ができなくなりました。今後比較を行う場合には、ActionController::Parameters#new
でハッシュを変換する必要があります。また、ActionController::ParametersからHashにあるメソッドの一部が廃止されています。
まとめ
Rails 5.1はReact / webpack / Yarnのサポートなどフロントエンド周りの新機能と共に、form_with
タグやtag
ヘルパの文法変更など、主にJavaScriptアセットやView部分の変更が大きいリリースとなりそうです。将来的な変更に備え、今からアップグレードの準備しておきましょう。