今から知っておきたいRails 5の新機能・変更点

  • 414
    いいね
  • 0
    コメント

はじめに

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 5.1での変更点については、 以下の記事も参照してください。
ReactやwebpackもサポートしたRails 5.1の新機能・変更点

新機能

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のみにする場合は、こちらを参考にしてください。

Rails API to Be Part of Rails 5

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

詳細なコード例についてはこちらを参考にしてください。

rails/actioncable

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

rakeコマンドで実行する各種タスクがrailsコマンドでも実行できるようになりました。

たとえば、DBのマイグレーションはrails db:migrate、ルーティングの確認はrails routesで行えるようになっています。

Implement rake proxy for rails cli

Turbolinks 5

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

<div id="nav" data-turbolinks-permanent></div>
<div id="footer" data-turbolinks-temporary></div>

rails/turbolinks

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

詳細については以下のリファレンスを参照してください。

ActiveRecord::Attributes::ClassMethods

機能追加

クエリ関連のメソッド追加(#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も追加されています。

Added #or to ActiveRecord::Relation
added ActiveRecord::Relation#outer_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"]

Add Enumerable#pluck
Add Enumerable#without

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

レコードの保存時に#saveメソッドのオプションにtouch: falseを渡すことで、タイムスタンプを更新しないようにできるようになりました。

以下の例では、articleというモデルオブジェクトのデータを更新した後も、updated_atの値は同じになります。

updated_at = article
artile.save!(touch: false)
article.update_at == updated_at
=> true

Provide :touch option to save() to accommodate saving without updating t...

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

データ件数が大きなモデルに対して処理を行うActiveRecord#find_in_batchesがブロックに配列を渡してレコードを渡すのに対して、ActiveRecord#in_batchesメソッドは、ブロックに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

in_batches using ids

変更点

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

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

belongs_to should default to required: 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にメソッドなどを追加すればよいことになります。

Introduce ApplicationRecord, an Active Record layer supertype

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

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

class ApplicationJob < ActiveJob::Base
end

Add explicit base class for ActiveJob jobs

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

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

Make AC::Parameters not inherited from Hash

alias_method_chainが非推奨に

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

Rails 5, Module#prepend, and the End of alias_method_chain

まとめ

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

参考サイト

rails/rails
Rails 5.0.0.beta1: Action Cable, API mode, Rails command
This week in Rails: Rails 5 - The Beta Awakens