Edited at

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

More than 1 year has passed since last update.


この記事で説明していること


  • アソシエーションでどんなことが出来るか

  • アソシエーションとは?

  • 多対多のアソシエーションとはなにか

  • 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を使わない場合


terminal

$ bundle exec rails g model user


migrationファイルの中身を書き換えます。

とりあえずnameとemailを加えました。


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します。


terminal

$ bundle exec rake db:migrate


---deviseを使ってログイン機能を実装している場合---


terminal

$ bundle exec rails g devise User


migrateします。


terminal

$ bundle exec rake db:migrate




モデルとテーブルの作成2(group)


terminal

$ bundle exec rails g model group


マイグレーションファイルを以下のように変更。

今回はnameを付け加えました。


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します。


terminal

$ bundle exec rake db:migrate




モデルとテーブルの作成3(group_user)

ここでgroupとuserの間を結ぶ中間テーブルを作成しますが、

そこでreferenceというパラメータを使います。

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


terminal

$ bundle exec rails g model group_user user:references group:references


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


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します。


terminal

$ bundle exec rake db:migrate




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

・user.rb

userはたくさんのgroup_userを持っていて、

group_userを通してたくさんのgroupを持っています。

中間テーブルを通して繋がっているものには

through: :group_usersというkeyをつけます。


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を更新できるようにしています。


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に属しています。

よって、このように記述します。


group_user.rb

class GroupUser < ApplicationRecord

belongs_to :user
belongs_to :group
end



何ができるのか?

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

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


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を取り出す。】

というような動作が出来るようになります。


index.html

- @group.group_users.each do |group_user|

= group_user.user.name

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


controller

@groups = current_user.groups



間違いや足りないところがございましたら、

どうぞご指摘お願いいたします!


最近買った、面白いもの

・ハンターハンター34巻(6/29)

クロロ VS ヒソカとか、どうやっても面白くなるとしか

・カーテン自動開閉ロボット

カーテンレールに付ける4000円のロボット。

これを付けてから目覚ましなしで起きられる率が上がった。

・衛藤美彩 写真集

「綺麗なお姉さん」が好きな人、ちょっと眺めてるだけで幸せになれますよ。


参考サイト様

Qiita

Rails4でcollection_check_boxesを使って、多対多の関連をチェックボックスで設定する

railsで多対多な関係を実装する時のポイント(加筆修正するかも)

複数の子レコードを作成・更新する. accepts_nested_attributes_for

いつも忘れる「Railsのgenerateコマンド」の備忘録