この記事で説明していること
- アソシエーションでどんなことが出来るか
- アソシエーションとは?
- 多対多のアソシエーションとはなにか
- 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を使わない場合
$ bundle exec rails g model user
migrationファイルの中身を書き換えます。
とりあえずnameとemailを加えました。
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します。
$ bundle exec rake db:migrate
---deviseを使ってログイン機能を実装している場合---
$ bundle exec rails g devise User
migrateします。
$ bundle exec rake db:migrate
モデルとテーブルの作成2(group)
$ bundle exec rails g model group
マイグレーションファイルを以下のように変更。
今回はnameを付け加えました。
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します。
$ bundle exec rake db:migrate
モデルとテーブルの作成3(group_user)
ここでgroupとuserの間を結ぶ中間テーブルを作成しますが、
そこでreferenceというパラメータを使います。
reference(参照)はテーブル同士の関係性を示します。
$ bundle exec rails g model group_user user:references group:references
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します。
$ bundle exec rake db:migrate
モデル同士のアソシエーションの記述
・user.rb
userはたくさんのgroup_userを持っていて、
group_userを通してたくさんのgroupを持っています。
中間テーブルを通して繋がっているものには
through: :group_users
というkeyをつけます。
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を更新できるようにしています。
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に属しています。
よって、このように記述します。
class GroupUser < ApplicationRecord
belongs_to :user
belongs_to :group
end
何ができるのか?
@groupの持っているgroup_userの繋がっているuserのnameを取り出す。
コントローラーで@groupを設定する。
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を取り出す。】
というような動作が出来るようになります。
- @group.group_users.each do |group_user|
= group_user.user.name
他にもcurrent_userの所属しているグループを全て取り出す際に、以下のように記述出来たりします。
@groups = current_user.groups
間違いや足りないところがございましたら、
どうぞご指摘お願いいたします!
##最近買った、面白いもの
・ハンターハンター34巻(6/29)
クロロ VS ヒソカとか、どうやっても面白くなるとしか
・カーテン自動開閉ロボット
カーテンレールに付ける4000円のロボット。
これを付けてから目覚ましなしで起きられる率が上がった。
・衛藤美彩 写真集
「綺麗なお姉さん」が好きな人、ちょっと眺めてるだけで幸せになれますよ。
参考サイト様
Qiita
Rails4でcollection_check_boxesを使って、多対多の関連をチェックボックスで設定する
railsで多対多な関係を実装する時のポイント(加筆修正するかも)
複数の子レコードを作成・更新する. accepts_nested_attributes_for