テーブル同士を関連づける

# テーブル同士を関連づける

## 重要！関連づけの３ステップ

### いっこめ
```ruby:最初っからバージョン
$ bundle exec rails g model UserDetail postal_code:string address:string birthday:datetime user:references
```



```ruby:後付けバージョン
$ bundle exec rails g migration AddUserIdToArticles user:references
```

**user:references**
サブのモデルに**メインモデル:references**をつけて関連性を持たせる。

反映されると、

```ruby:schema.rb
ActiveRecord::Schema.define(version: 2019_02_05_020525) do

  create_table "articles", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
    t.string "title"
    t.string "body"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.bigint "user_id"
    t.index ["user_id"], name: "index_articles_on_user_id"
  end

# (中略)

  add_foreign_key "articles", "users" 　←　こんな感じに追加される
end
```



### にこめ

サブ.rb　ファイルに**belongs_to :メイン** を書き加える。

```ruby:サブ.rb
class Article < ApplicationRecord
  belongs_to :user
end
```

### さんこめ

メイン.rb に **has_many :サブ（複数形表記）** か **has_one :サブ（単数系表記）** を書き加える。

```ruby:1対多
class User < ApplicationRecord
  # (中略)

  has_many :articles
end
```

```ruby:1対1
class User < ApplicationRecord
  # (中略)

  has_one :user_detail
end
```

```ruby:多対多
class User < ApplicationRecord
  # (中略)

  has_many :user_communities
  has_many :communities, through: :user_communities
end
```

```ruby:多対多
class Community < ApplicationRecord
# (中略)

  has_many :user_communities
  has_many :users, through: :user_communities
end
```



## 1:多 の実装

```ruby
$ bundle exec rails c

user = User.first
user.articles
 Article Load (2.6ms)  SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` = 1
=> []
```


逆からも呼び出せてたら関連づけOK!!!


```ruby
$ bundle exec rails c
article = Article.first
article.user
 User Load (0.6ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> #<User:0x00007fcc4d8333a0
 id: 1,
 account: "chinju20190201",
 name: "珍獣",
 created_at: Fri, 01 Feb 2019 03:27:02 UTC +00:00,
 updated_at: Fri, 01 Feb 2019 03:27:02 UTC +00:00,
 email: "chinju@example.com">
```



データを流し込んで見よう！！！

```ruby
user = User.first
article = user.articles.new # これで、User.first の id の　Article インスタンスが作成される
article.title ="誰でもわかる Ruby"
article.body = "中身はまだない"
article.save!

article
=> #<Article:0x00007fcc4c4b2da8
id: 1,
title:"誰でもわかる Ruby",
body:"中身はまだない",
created_at: Tue, 05 Feb 2019 02:38:09 UTC +00:00,
updated_at: Tue, 05 Feb 2019 02:38:09 UTC +00:00,
user_id: 1> 
```


## 1:1 の実装

```ruby
$ bundle exec rails c

user = User.first
user.user_detail

UserDetail Load (0.6ms)  SELECT  `user_details`.* FROM `user_details` WHERE `user_details`.`user_id` = 1 LIMIT 1
=> nil
```


データを流し込んで見よう！！！　が、

1:1 の実装の時はnewがうまくいかない。ので、

```ruby
user_detail = UserDetail.new(user: user)

か

user_detail = UserDetail.new(user_id: user.id)
```

でnewしてからでないとデータの変更ができない。
特殊！！！！


## 多対多の実装

中間テーブルを実装しなければならない。

<img width="780" alt="many-many.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434376/78bebf4d-34db-57a6-3fba-027008a1bda3.png">


```ruby
$ bundle exec rails g model Community name:string
$ bundle exec rails g model UserCommunity user:references community:references
```

多対多の実装の場合は、中間テーブルにキーをどっちも持ってもらいましょう！！！
干渉しない。事故の時も保険屋がどっちも見るでしょ。


実装後のschema.rd

```ruby:schema.rd
ActiveRecord::Schema.define(version: 2019_02_05_050130) do
  # (中略)
  create_table "communities", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "user_communities", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
    t.bigint "user_id"
    t.bigint "community_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["community_id"], name: "index_user_communities_on_community_id"
    t.index ["user_id"], name: "index_user_communities_on_user_id"
  end

  # (中略)

  add_foreign_key "user_communities", "communities" ←こんな感じに追加されてる
  add_foreign_key "user_communities", "users"　←こんな感じに追加されてる

  # (中略)
end
```


確認する。

```ruby
$ bundle exec rails c

user = User.first
user.communities

  Community Load (0.6ms)  SELECT `communities`.* FROM `communities` INNER JOIN `user_communities` ON `communities`.`id` = `user_communities`.`community_id` WHERE `user_communities`.`user_id` = 1
=> []
```

```ruby
$ bundle exec rails c

user = User.first
user.communities.create!(name: "Java 苦手")
   (0.3ms)  BEGIN
  Community Create (2.8ms)  INSERT INTO `communities` (`name`, `created_at`, `updated_at`) VALUES ('Java苦手', '2019-02-05 05:40:07', '2019-02-05 05:40:07')
  UserCommunity Create (0.4ms)  INSERT INTO `user_communities` (`user_id`, `community_id`, `created_at`, `updated_at`) VALUES (1, 1, '2019-02-05 05:40:07', '2019-02-05 05:40:07')
   (6.4ms)  COMMIT

user = User.first
user.communities
  Community Load (0.5ms)  SELECT `communities`.* FROM `communities` INNER JOIN `user_communities` ON `communities`.`id` = `user_communities`.`community_id` WHERE `user_communities`.`user_id` = 1
=> [#<Community:0x00007fb2ed69f918
  id: 1,
  name: "Java苦手",
  created_at: Tue, 05 Feb 2019 05:40:07 UTC +00:00,
  updated_at: Tue, 05 Feb 2019 05:40:07 UTC +00:00>]
```


##おまけ

rails-erd という gem を使うと、rails で実装した内容に沿って、ER図を出力してくれる。
便利。

<img width="512" alt="rails-erd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434376/3b81177c-2665-b382-fad3-affd02831367.png">