ActiveRecordの機能まとめ


最近、開発でRuby on Railsを使用しています。
備忘録の為に、ActiveRecord関連のナレッジについてまとめていきます。

## accepts_nested_attributes_for

親子関係にあるModelのデータを画面で入力し、一回のsubmitで更新する場合がある。
その場合は、以下のように`has_many`と`accepts_nested_attributes_for`も指定する。

```user.rb
class User < ApplicationRecord
  has_many: addresses
  accepts_nested_attributes_for : addresses, reject_if: :all_blank
end
```

上記を指定するとviewで`fields_for`を使ってネスト表示することが可能。

## alias_attribute
`alias_attribute`はフィールドにaliasで別名を定義するときに使います。

```user.rb
class User < ApplicationRecord
  alias_attribute :status, :member_type
end
```

元々のフィールドのバリデーションの設定を引き継ぐので、処理に応じて分けたい場合は便利ですね。

## attr_accessor

DB存在しないカラム等に、画面のみで使用するプロパティとして設定するときに使用します。

```user.rb
class User < ApplicationRecord
  attr_accessor :use_phone_number
end
```

## enum

### Modelの定義方法
`enum`とは[列挙型](https://ja.wikipedia.org/wiki/列挙型)と呼ばれるデータ型です。
ActiveRecordでは、カラムに登録可能なデータ群を定義するときに使います。

```user.rb
class User < ApplicationRecord
  enum member_type: {guest: 0, admin: 1, master: 2}
end
```

定義できる値は上記の数値（`integer`）以外に、論理値(`boolean`)、文字列(`string`)、さらには以下のように配列でも定義可能です。

```User.rb
class User < ApplicationRecord
  enum member_type: [:guest, :admin, :master]
end
```

### 値の使用方法
```users_controller.rb
user = User.new(member_type: :admin)
user.member_type // 1
user.admin? // true
user.master! // 値を:masterへ変更
```

### 検索条件
`enum`を定義しているカラムは、クエリーとしても使用可能です。

```
User.active.guest
```

## includes

`belongs_to`や`has_one`、`has_many`で指定したModelも一緒に参照する際に使用する。

```user.rb
class User < ApplicationRecord
  has_many: addresses
end
```

```user_controller.rb
def index
  users = User.all
  users.each do |user|
    puts user.name
    user.addresses.each do |address|
      puts address.zipcode
    end
  end
end
```

上記のようなケースの場合、`User.all`で`select * from users`がSQLとして実行されます。
その後、`@users.each`内部で`has_many`の`address`テーブルに対してeachの回数分、`select * from adreesses where adreesses.id = ? `がSQLとして実行されます。

これは`N+1問題`と呼ばれるケースですね。
（`N+1問題`についてはここでは割愛します。）

それを解消するために、includesを使用します。以下のように変更します。

```user_controller.rb
def index
  users = User.all.includes(:addresses)
  …
end
```

そうすると`User.all`の実行時に、以下の2つのSQLが実行されます。

```
select * from users;
select * from addresses where id in (...)
```

SQLの実行回数が抑えられますが、検索条件が`in`のため、インデックスが効かない場合があるので、使用時には少し注意しましょう。

## scope

`scope`とはActiveRecordのクエリーの条件を関数のように汎用的に使える機能です。

```user.rb
class User < ApplicationRecord
  scope :active, -> { where(deleted: false) }
end
```

上記は`users`テーブルで`deleted`フラグが有効でない、アクティブユーザーを検索するクエリーを`scope`にまとめたものです。
コントローラーで以下のように使えます。

```users_controller.rb
users = User.active
```

## Concern

ConcernはActiveRecordではなく、ActiveSupportのオブジェクトなのですが、Modelでも使う機会が多いので、記載しておきます。
Concernとは各Model間、Controller-Model間で共通に使う処理がある場合に定義して使います。
Rubyにはmix-inと呼ばれる共通処理群をモジュールとして組み込む機能があります。
以下のようにして使うことが出来ます。

```user.rb
include action
```


## 参考
* [Rails Modelのscopeとlambda](http://qiita.com/shizuma/items/fe695fe8a07aee031f01)
* [Rails enumについてまとめておく](http://qiita.com/shizuma/items/d133b18f8093df1e9b70)
* [列挙型](https://ja.wikipedia.org/wiki/列挙型)
* [Railsでロジックを書く場所を意識する](http://qiita.com/kanekomasanori@github/items/daf93f95c77c629d070f)
* [[Rails] ActiveSupport::Concern の存在理由](http://qiita.com/castaneai/items/6dc121ce6ff100614f42)
* [Rails で includes して N+1 問題対策](http://qiita.com/hirotakasasaki/items/e0be0b3fd7b0eb350327)
* [ActiveRecord の has_many関連、件数を調べるメソッドはどれを使えばいい？](http://qiita.com/nay3/items/1cda39fb58569d832203)