LoginSignup
425
432

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-01-19

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

  • アソシエーションでどんなことが出来るか
  • アソシエーションとは?
  • 多対多のアソシエーションとはなにか
  • 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コマンド」の備忘録

425
432
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
425
432