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

# はじめに

Ruby 2.3のリリース前に、Ruby on Railsのバージョン5.0系列（以下Rails 5）の最初のベータ版が[リリース](http://weblog.rubyonrails.org/2015/12/18/Rails-5-0-beta1/)されました。

Rails 5は、JSON APIサーバーやWebSocketサーバー用の新機能を導入するとともに、Ruby 2.2.2以上で動作するため内部的には大きな変更が加えられています。また、モデルが`ApplicationRecord`から継承されたり、Rakeタスクを`rails`コマンドで実行できるようになったりといった基本的な部分にも大きく手を加えられています。

本記事では、[GitHubのRailsプロジェクト](https://github.com/rails/rails)のIssuesやPull Requestsの履歴をもとに、Rails 5の主要な新機能・変更点の紹介を行います。

※ 他のバージョンのRailsの主要な新機能・機能追加・変更点については以下を参照してください。

- [ReactやwebpackもサポートしたRails 5.1の新機能・変更点 - Qiita](https://qiita.com/ryohashimoto/items/a8ba7bb8d6f340894188)
- [Ruby on Rails 5.2の新機能（Active Storage, Content Security Policyなど） - Qiita](https://qiita.com/ryohashimoto/items/75f48fa5a3846c58f735)
- [Ruby on Rails 6の主要な新機能・機能追加・変更点](https://qiita.com/ryohashimoto/items/622c3bcfb3336cb9317e)
# 新機能

## Rails API

`ActionController::Base`の代わりに`ActionController::API`をコントローラで継承することによって、JSON APIサーバー用の軽量なRailsアプリケーションを構築することができるようになりました。

完全にAPIのみのRailsアプリケーションを作成する場合は、`rails new`で`--api`オプションを指定します。

```console
$ rails new my_api --api
```

これによって、以下のことが行われます。
1. APIサーバーを動かすのに最低限のミドルウェアがロードされます。
2. アプリケーション内に生成される`ApplicationController`は、`ActionController::API`を継承するようになります。
3. ジェネレータでの、ビューやアセットの生成が行われません。

既存のRailsアプリケーションをAPIのみにする場合は、[こちら](http://edgeguides.rubyonrails.org/api_app.html)を参考にしてください。

[Rails API to Be Part of Rails 5](https://wyeworks.com/blog/2015/4/20/rails-api-is-going-to-be-included-in-rails-5/)

## Action Cable

Action Cableを用いることで、リアルタイムな双方向通信を可能にする[WebSocket](https://ja.wikipedia.org/wiki/WebSocket)の機能をRailsアプリケーションに簡単に追加することが可能になりました。Action Cableには、サーバーとクライアントの両方の機能が含まれています。

サーバー側では、`ApplicationCable::Connection`や`ApplicationCable::Channel`などのクラスを用いて実装を行い、クライアント側では、CoffeeScript（JavaScript）の`App.cable.subscriptions.create`によってサーバー側の`AppearanceChannel#subscribed`メソッドを呼び出します。

ジェネレータでサーバーとクライアントの両方のコードを生成することができます。以下は`chat`というchannelを生成する例です。

```console
$ rails generate channel chat
```

詳細なコード例については[こちら](https://github.com/rails/rails/blob/master/actioncable/README.md)を参考にしてください。

[rails/actioncable](https://github.com/rails/actioncable)

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

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

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

[Implement rake proxy for rails cli](https://github.com/rails/rails/pull/22288)

## Turbolinks 5

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

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

[rails/turbolinks](https://github.com/rails/turbolinks)

## Sprockets 3のサポート

Rails 4までは`config/initializers/assets.rb`でどのアセットをプリコンパイルするか指定していましたが、Rails 5では`app/assets/config/`ディレクトリ内の`manifest.js`で指定します。

アプリケーションの初期状態では、`manifest.js`は以下のようになっています。

```js
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
```

（以下の参考ページでは、Sprockets 4となっていますが、現在はまだSprockets 3です）
[Rails 5: The Sprockets 4 Manifest](http://eileencodes.com/posts/the-sprockets-4-manifest/)

## `ActiveRecord::Attributes`

モデルの`attribute`で属性を指定することで、モデルの属性をSQLで取得したり、`ActiveRecord::Relation`の`where`メソッドに渡したりする方法をカスタマイズできるようになりました。たとえば、以下のようにDB上では`decimal`型で定義された属性を

```ruby
create_table :store_listings, force: true do |t|
  t.decimal :price_in_cents
end
```

`attribute`で、`integer`を指定することで、整数に変換することができます。

```ruby
class StoreListing < ActiveRecord::Base
  attribute :price_in_cents, :integer
end
```

`attribute`で変換を行う前後では以下のように異なります。

```ruby
# before
store_listing.price_in_cents
=> BigDecimal.new(10.1)
# after
store_listing.price_in_cents
=> 10
```

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

[ActiveRecord::Attributes::ClassMethods](http://edgeapi.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html)

# 機能追加

## クエリ関連のメソッド追加（`#or`, `#left_outer_joins`, `#left_joins`）

`ActiveRecord::Relation`にSQLでOR条件を指定できる`#or`や外部結合を行う`#left_outer_joins`のメソッドが追加されました。

```ruby
Post.where('id = 1').or(Post.where('id = 2'))
=> SELECT * FROM posts WHERE (id = 1) OR (id = 2)
```

```ruby
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](https://github.com/rails/rails/pull/16052)
[added ActiveRecord::Relation#outer_joins](https://github.com/rails/rails/pull/12071)

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

特定のレコードのカラムを配列にする`#pluck`メソッドと似た挙動のメソッドがハッシュの配列でも使えるようになりました。

```ruby
[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
=> ["David", "Rafael", "Aaron"]
```

また、配列の中から特定の要素を除く`#without`メソッドが追加されました。

```ruby
people = ["David", "Rafael", "Aaron", "Todd"]
people.without "Aaron", "Todd"
=> ["David", "Rafael"]
```

[Add Enumerable#pluck](https://github.com/rails/rails/pull/20350)
[Add Enumerable#without](https://github.com/rails/rails/pull/19157)

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

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

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

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

[Provide :touch option to save() to accommodate saving without updating t...](https://github.com/rails/rails/pull/18225)

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

データ件数が大きなモデルに対して処理を行う`ActiveRecord#find_in_batches`がブロックに配列を渡してレコードを渡すのに対して、`ActiveRecord#in_batches`メソッドは、ブロックに`ActiveRecord::Relation`を渡せるようになりました。オプションに`of`を渡すことで、バッチのサイズを変更することができます。（デフォルトは1000）

```ruby
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](https://github.com/rails/rails/pull/20933)

# 変更点

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

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

[belongs_to should default to required: true](https://github.com/rails/rails/issues/18233)

## Active Recordのモデルが`ApplicationRecord`から継承されるように

Rails 5で新しくアプリケーションを作成した場合、`app/models/application_record.rb`が以下のように作成され、他のモデルを生成する際も、`ActiveRecord::Base`ではなく、`ApplicationRecord`から継承を行うようになりました。

```ruby
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end
```

これまでは、アプリケーションのモデル全体にある機能を追加したい場合は、`ActiveRecord::Base`にモンキーパッチを行うか、それぞれのモデルのクラスにモジュールをincludeする必要がありましたが、Rails 5以降では、`ApplicationRecord`にメソッドなどを追加すればよいことになります。

[Introduce ApplicationRecord, an Active Record layer supertype](https://github.com/rails/rails/pull/22567)

## Active Jobのジョブも`ApplicationJob`から継承されるように

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

```ruby
class ApplicationJob < ActiveJob::Base
end
```
[Add explicit base class for ActiveJob jobs](https://github.com/rails/rails/pull/19034)

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

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

[Make AC::Parameters not inherited from Hash](https://github.com/rails/rails/pull/20868)

## `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`](http://www.justinweiss.com/articles/rails-5-module-number-prepend-and-the-end-of-alias-method-chain/)

# まとめ

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

# 参考サイト

[rails/rails](https://github.com/rails/rails)
[Rails 5.0.0.beta1: Action Cable, API mode, Rails command](http://weblog.rubyonrails.org/2015/12/18/Rails-5-0-beta1/)
[This week in Rails: Rails 5 - The Beta Awakens](http://weblog.rubyonrails.org/2015/12/19/this-week-in-rails-rails-5-the-beta-awakens/)