railsで多対多のアソシエーションの作り方と、出来ること

# この記事で説明していること
- アソシエーションでどんなことが出来るか
- アソシエーションとは？
- 多対多のアソシエーションとはなにか
- railsで多対多のアソシエーションを作り方

## アソシエーション（関連付け）で出来ること
あるuserの持っているtweetを全て取り出してくる。
あるgroupの持っているuserのnameを全て取り出してくる。などなど....

関連性を設定することによって、繋がった先のものから変数を取り出せることがアソシエーションのメリットです。


## そもそもアソシエーション（関連付け）って何？
アソシエーションとは、モデル同士の関係性を設定することです。

(例)
userはtweetをたくさん持っている。
tweetはただ1人のuserに属する。



## 多対多のアソシエーションとは何か

userとgroupがあるWEBアプリケーションを考えた時、

group：userをたくさん持つ
user ：たくさんのgroupに所属する

**groupとuserが "複数 - 複数" の関係**になっています。
このような状態を**多対多の状態**と言います。

このような時には中間テーブルというものを作りデータを管理することになります。（他の方法もありますが、、）

### ***中間テーブルとは？***
`group -- group_user -- user`のように2つのテーブルの間を繋ぐものです。

**group_userのテーブル**

| id | user_id | group_id |
|:-:|:-:|:-:|
|1|3|2|
|2|2|5|
|3|1|6|

上記のように***両方のテーブルのデータを1つのレコード（横列）で持ちます。***

# railsで多対多のアソシエーションを作る
手順
- rails g model でモデルとテーブルのmigrationファイルを作成
- migrationファイルの中身を書き換える
- migrateしてテーブルを作成
- ----上記を user, group, group_userの3回行う
- モデルのアソシエーションを記述する


***

#### モデルとテーブルの作成1（user）

deviseを使わない場合

```ruby:terminal
$ bundle exec rails g model user
```

migrationファイルの中身を書き換えます。
とりあえずnameとemailを加えました。

```ruby:migration_file
class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string  :name, null: false
      t.string  :email, null: false, unique: true 
      t.timestamps
    end
  end
end
```

そして、migrateします。

```ruby:terminal
$ bundle exec rake db:migrate
```
***---deviseを使ってログイン機能を実装している場合---***

```ruby:terminal
$ bundle exec rails g devise User
```

migrateします。

```ruby:terminal
$ bundle exec rake db:migrate
```

***
#### モデルとテーブルの作成2（group）

```ruby:terminal
$ bundle exec rails g model group
```

マイグレーションファイルを以下のように変更。
今回はnameを付け加えました。

```ruby:migraion_file
class CreateGroups < ActiveRecord::Migration[5.0]
  def change
    create_table :groups do |t|
      t.string  :name, null: false, unique: true
      t.timestamps
    end
  end
end
```

migrateします。

```ruby:terminal
$ bundle exec rake db:migrate
```
***
#### モデルとテーブルの作成3（group_user）

ここでgroupとuserの間を結ぶ中間テーブルを作成しますが、
そこで**reference**というパラメータを使います。

reference（参照）はテーブル同士の関係性を示します。

```ruby:terminal
$ bundle exec rails g model group_user user:references group:references
```

migration_fileが以下のようになっているのを確認します。

```ruby:migration_file
class CreateGroupUserTable2 < ActiveRecord::Migration[5.0]
  def change
    create_table :group_users do |t|
      t.references  :user,  index: true, foreign_key: true
      t.references  :group, index: true, foreign_key: true
      t.timestamps
    end
  end
end
```

その後、migrateします。

```ruby:terminal
$ bundle exec rake db:migrate
```
***

### モデル同士のアソシエーションの記述



・user.rb
userはたくさんのgroup_userを持っていて、
group_userを通してたくさんのgroupを持っています。

中間テーブルを通して繋がっているものには
`through: :group_users`というkeyをつけます。

```ruby:user.rb
class User < ApplicationRecord
  has_many :groups, through: :group_users
  has_many :group_users
end
```

・group.rb
User.rbとほぼ同じです。
`accepts_nested_attributes_for` というkeyは、
***他のモデルを一括で更新、保存できるようにする***ものです。
ここではgroupを保存するのと同時にgroup_usersを更新できるようにしています。

```ruby:group.rb
class Group < ApplicationRecord
	has_many :users, through: :group_users
	has_many :group_users
	accepts_nested_attributes_for :group_users
end

```
・group_user.rb

group_userは1つのuser、1つのgroupに属しています。
よって、このように記述します。

```ruby:group_user.rb
class GroupUser < ApplicationRecord
  belongs_to :user
  belongs_to :group
end
```
***

# 何ができるのか？

***@groupの持っているgroup_userの繋がっているuserのnameを取り出す。***

コントローラーで@groupを設定する。

```ruby:controller
class MessagesController < ApplicationController
  def index
    @group = Group.find(params[:group_id])
  end
end
```

ビューの中で、@groupの持っているgroup_userを
group_usersと***複数形にする***ことで配列として取り出します。

each文の中で`group_user.user.name`とすることで
***【@groupの持っているgroup_userの繋がっているuserのnameを取り出す。】***
というような動作が出来るようになります。

```haml:index.html
- @group.group_users.each do |group_user|
  = group_user.user.name
```

他にもcurrent_userの所属しているグループを全て取り出す際に、以下のように記述出来たりします。

```ruby:controller
@groups = current_user.groups
```

***

間違いや足りないところがございましたら、
どうぞご指摘お願いいたします！

##最近買った、面白いもの
[・ハンターハンター34巻（6/29）](http://amzn.to/2u6iUc4)
クロロ VS ヒソカとか、どうやっても面白くなるとしか
[・カーテン自動開閉ロボット](http://amzn.to/2u6LHwS)
カーテンレールに付ける4000円のロボット。
これを付けてから目覚ましなしで起きられる率が上がった。
[・衛藤美彩 写真集](http://amzn.to/2tcFfIz)
「綺麗なお姉さん」が好きな人、ちょっと眺めてるだけで幸せになれますよ。

### 参考サイト様
Qiita
[Rails4でcollection_check_boxesを使って、多対多の関連をチェックボックスで設定する](http://qiita.com/hamichamp/items/8cf980e6d5ca9fd7e96f)
[railsで多対多な関係を実装する時のポイント（加筆修正するかも）](http://qiita.com/rojiuratech/items/0487105994d9281221d4)
[複数の子レコードを作成・更新する. accepts_nested_attributes_for](http://qiita.com/hmuronaka/items/818c421dc632e3efb7a6)

[いつも忘れる「Railsのgenerateコマンド」の備忘録](http://maeharin.hatenablog.com/entry/20130212/rails_generate)