2016年5月24日火曜日

Rails 5の新機能・変更点

はじめに

Ruby 2.3のリリース前に、Ruby on Railsのバージョン5.0系列(以下Rails 5)の最初のベータ版がリリースされました。
Rails 5は、JSON APIサーバーやWebSocketサーバー用の新機能を導入するとともに、Ruby 2.2.2以上で動作するため内部的には大きな変更が加えられています。また、モデルがApplicationRecordから継承されたり、Rakeタスクをrailsコマンドで実行できるようになったりといった基本的な部分にも大きく手を加えられています。
本記事では、GitHubのRailsプロジェクトのIssuesやPull Requestsの履歴をもとに、Rails 5の主要な新機能・変更点の紹介を行います。

新機能

Rails API

ActionController::Baseの代わりにActionController::APIをコントローラで継承することによって、JSON APIサーバー用の軽量なRailsアプリケーションを構築することができるようになりました。
完全にAPIのみのRailsアプリケーションを作成する場合は、rails new--apiオプションを指定します。
$ rails new my_api --api
これによって、以下のことが行われます。
1. APIサーバーを動かすのに最低限のミドルウェアがロードされます。
2. ApplicationControllerは、ActionController::APIを継承するようになります。
3. ジェネレータでの、ビューやアセットの生成が行われません。
既存のRailsアプリケーションをAPIのみにする場合は、こちらを参考にしてください。

Action Cable

Action Cableを用いることで、リアルタイムな双方向通信を可能にするWebSocketの機能をRailsアプリケーションに簡単に追加することが可能になりました。Action Cableには、サーバーとクライアントの両方の機能が含まれています。
サーバー側では、ApplicationCable::ConnectionやApplicationCable::Channelなどのクラスを用いて実装を行い、クライアント側では、CoffeeScript(JavaScript)のApp.cable.subscriptions.createによってサーバー側のAppearanceChannel#subscribedメソッドを呼び出します。
ジェネレータでサーバーとクライアントの両方のコードを生成することができます。以下はchatというchannelを生成する例です。
$ rails generate channel chat
詳細なコード例についてはこちらを参考にしてください。

rakeタスクをrailsコマンドから実行できるように

rakeコマンドで実行する各種タスクがrailsコマンドでも実行できるようになりました。
たとえば、DBのマイグレーションはrails db:migrate、ルーティングの確認はrails routesで行えるようになっています。

Turbolinks 5

data-turbolinks-permanentをDOM要素につけることでページ間で保持されるようになり、状態の初期化を必要としないので、より高速に動作するようになりました。
サイドバーなど、ページ間で固定の要素の場合は、data-turbolinks-permanentを付与し、ページ間で保持しない要素は、daa-turbolinks-temporaryをつけると良いようです。
id="nav" data-turbolinks-permanent>
id="footer" data-turbolinks-temporary>

Sprockets 3のサポート

Rails 4まではconfig/initializers/assets.rbでどのアセットをプリコンパイルするか指定していましたが、Rails 5ではapp/assets/config/ディレクトリ内のmanifest.jsで指定します。
アプリケーションの初期状態では、manifest.jsは以下のようになっています。
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
(以下の参考ページでは、Sprockets 4となっていますが、現在はまだSprockets 3です)
Rails 5: The Sprockets 4 Manifest

ActiveRecord::Attributes

モデルのattributeで属性を指定することで、モデルの属性をSQLで取得したり、ActiveRecord::Relationのwhereメソッドに渡したりする方法をカスタマイズできるようになりました。たとえば、以下のようにDB上ではdecimal型で定義された属性を
create_table :store_listings, force: true do |t|
  t.decimal :price_in_cents
end
attributeで、integerを指定することで、整数に変換することができます。
class StoreListing < ActiveRecord::Base
  attribute :price_in_cents, :integer
end
attributeで変換を行う前後では以下のように異なります。
# before
store_listing.price_in_cents
=> BigDecimal.new(10.1)
# after
store_listing.price_in_cents
=> 10
詳細については以下のリファレンスを参照してください。

クエリ関連のメソッド追加(#or, #left_outer_joins, #left_joins)

ActiveRecord::RelationにSQLでOR条件を指定できる#orや外部結合を行う#left_outer_joinsのメソッドが追加されました。
Post.where('id = 1').or(Post.where('id = 2'))
=> SELECT * FROM posts WHERE (id = 1) OR (id = 2)
User.left_outer_joins(:posts)
=> SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
また、#left_outer_joinsのエイリアスの#left_joinsも追加されています。

Enumerableモジュールに#pluckと#withoutが追加

特定のレコードのカラムを配列にする#pluckメソッドと似た挙動のメソッドがハッシュの配列でも使えるようになりました。
[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
=> ["David", "Rafael", "Aaron"]
また、配列の中から特定の要素を除く#withoutメソッドが追加されました。
people = ["David", "Rafael", "Aaron", "Todd"]
people.without "Aaron", "Todd"
=> ["David", "Rafael"]

ActiveRecordの#saveにtouchオプションが追加

レコードの保存時に#saveメソッドのオプションにtouch: falseを渡すことで、タイムスタンプを更新しないようにできるようになりました。
以下の例では、articleというモデルオブジェクトのデータを更新した後も、updated_atの値は同じになります。
updated_at = article
artile.save!(touch: false)
article.update_at == updated_at
=> true

ActiveRecord::Relation#in_batchesメソッドが追加

データ件数が大きなモデルに対して処理を行うActiveRecord#find_in_bathcesがブロックに配列を渡してレコードを渡すのに対して、ActiveRecord#in_bathcesメソッドは、ブロックにActiveRecord::Relationを渡せるようになりました。オプションにofを渡すことで、バッチのサイズを変更することができます。(デフォルトは1000)
Person.in_batches.each_record(&:party_all_night!)
Person.in_batches.update_all(awesome: true)
Person.in_batches.delete_all
Person.in_batches.each do |relation|
  relation.delete_all
  sleep 10 # Throttles the delete queries
end

変更点

belongs_toの参照先がnilの場合はバリデーションエラーに

Rails 4以前の挙動に戻すには、belongs_toのオプションでoptional: trueを指定する必要があるそうです。

ActiveRecordのモデルがApplicationRecordから継承されるように

Rails 5で新しくアプリケーションを作成した場合、app/models/application_record.rbが以下のように作成され、他のモデルを生成する際も、ActiveRecord::Baseではなく、ApplicationRecordから継承を行うようになりました。
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end
これまでは、アプリケーションのモデル全体にある機能を追加したい場合は、ActiveRecord::Baseにモンキーパッチを行うか、モジュールをincludeする必要がありましたが、Rails 5以降では、ApplicationRecordにメソッドなどを追加すればよいことになります。

ActiveJobのジョブもApplicationJobから継承されるように

ActiveJobに関しても同じく、各ジョブはActiveJob::Baseではなく、以下のapp/jobs/application_job.rbで記述される、ApplicationJobから継承を行うようになりました。
class ApplicationJob < ActiveJob::Base
end

ActionController::Parametersが、ハッシュから継承されなくなった

これまでのParametersが、ActiveSupport::HashWithIndifferentAccessから継承されていてEnumerableモジュールの各メソッドで許可されていないパラメータを操作される危険性があったので変更したとのことです。(既存のハッシュなどのメソッドを使用している場合は、アップグレードの際に注意が必要です。)

alias_method_chainが非推奨に

Rails 5では、Ruby 2.2.2以上を使用するので、ActiveSupportのalias_method_chainではなくRubyのModule#prependを使用するようになっています。

まとめ

Rails 5は、Rails APIやAction Cableなどこれまで以上にアプリケーションの幅を広げ、各種クエリ関連のメソッドなどが追加されたのでかゆい部分に手がとどくバージョンとなっているようです。すでにベータ版がリリースされているので、新機能を試したり、既存のRails 4アプリケーションのアップグレードを行ってみたりしてはいかがでしょうか。

0 件のコメント:

コメントを投稿