【Rails】アソシエーションを使ってみる

#はじめに
現在独学で未経験からWebプログラマーを目指しているものです。アウトプットとして記事を書いています。初学者の方にお役に立てれば幸いです。
#なぜアソシエーションを使うのか
アソシエーションとはモデル同士の関連付けを行うために必要となるものです。
Twitterなどでは一人のユーザーが１つまたは多数の投稿を行なっています。例えばuser1というユーザーがtweet1という投稿を行なったとします。アソシエーションを使わなかった場合、tweet1を投稿したユーザーのモデルに格納されているemailなどのデータを取り出したいときに大変厄介になってしまいます。
アソシエーションはこのモデル間にキーを設けることにより関連性を持たせることができます。

![aso1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/717893/8b897026-2b79-1586-c7a5-42e3e37d2e32.jpeg)

#関連付けの種類について
アソシエーションを使うことで各モデル間に関係性を持たせることができることがわかりました。ところで前述で書いた**user1**はたくさんの**tweet**を保有しています。また、**tweet1**は**user1**に属しているものとして考えられます。この関係性から**user1が親**、**tweet1が子**の関係であるといえます。親子の関係性は今後重要になってきます。

##1.１対１
アソシエーションの種類は３通りあります。まず1対1について紹介します。これはユーザー１人に対しアイコン画像１つが対応するときなどに使う関連付けです。
まずログイン機能をつけるものとし、deviseでUserモデルを管理したいと思います。
Gemfileに以下を記述します。

```ruby:Gemfile
gem 'devise' #追加
```

bundle installします。

```shell:ターミナル
$bundle install
```

次にdeviseのインストールとUserモデルを作成します。

```shell:ターミナル
$rails g devise:install
$rails g devise User  
```

Userモデルに対応する画像モデルはImageとします。

```shell:ターミナル
$rails g model Image user_id:integer
$rails db:migrate
```
ここで重要なのは**user_id:integer**をカラムとして追加している点です。最初にモデル間の関係を持たせるにはキーが必要だといいました。なので**(モデル名)_id**という形でカラムを追加しておきましょう。

ここからアソシエーションの機能をつけていきます。ImageモデルがUserモデルに従属している、つまり**Userが親、Imageが子の関係**であるためここでは、親のUserモデルには**has_one**を利用します。Userモデルに下記の１行を追加します。

```app/models/user.rb

class Account < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one :image #追加

```

また従属している側のImageモデルには**belongs_to**を使います。

```app/models/image.rb

class Account < ApplicationRecord
  belongs_to :user #追加
end
```

##2.１対多
ユーザー１人が多くのtweetを投稿するときなどには１対多のアソシエーションを利用します。
まずTweetモデルを作ります。Imageと同様にuser_id:integerを追加します。

```shell:ターミナル
$rails g model Tweet body:text user_id:integer
$rails db:migrate
```

１対１はhas_oneを利用したのに対し、１対多ではUserがたくさんのTweetを保有することになるため**has_many**をUserモデルに追加します。**子のTweetモデルは複数形にします。**

```app/models/user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one :image 
  has_many :tweets #追加

```

Tweetモデルには1対1と同様です。


```app/models/tweet.rb

class Tweet < ApplicationRecord
  belongs_to :user #追加
end
```


##3.多対多
いいねやコメント機能の実装などに必要となります。多対多ではお互いがどのUserがどのTweetにいいねをしたかを整理するために、中間テーブルを作成する必要があります。これによりUser1がいいねしたTweetの数、Tweet1がどれくらいのUserからいいねされたかを把握することができます。

まず中間テーブルFavoriteモデルを作成します。

```shell:ターミナル
$rails g model Favorite user_id:integer tweet_id:integer
$rails db:migrate
```

Userモデル、Tweetモデルは多くのFavoriteをもっていると考えられるので、

```app/models/user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one :image 
  has_many :tweets
  has_many :favorites #追加
```

```app/models/tweet.rb

class Tweet < ApplicationRecord
  belongs_to :user 
  has_many :favorites #追加
end
```

Favoriteモデルは子なので

```app/models/favorite.rb
class Favorite < ApplicationRecord
    belongs_to :user
    belongs_to :tweet
end
```

となります。

#まとめ

- 従属関係（親、子）の関係を決める
- 親のモデルでは、1対1のときはhas_oneメソッド、１対多と多対多はhas_manyメソッドを使う
- 子のモデルではbelongs_toメソッドを使う





#参考
[【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】](https://qiita.com/kazukimatsumoto/items/14bdff681ec5ddac26d1)