LoginSignup
58
60

More than 5 years have passed since last update.

Rails 多対多テーブルのModelの書き方~お気に入り・フォロー機能を例に~

Last updated at Posted at 2015-05-07

多対多テーブル Modelの書き方を
・お気に入り機能(comment<->favorite_comment<->user)
・フォロー機能(user<->follow_user<->user)
の2つを例にして紹介する。

お気に入り機能

ユーザー(users)がコメント(comments)をお気に入りする

テーブル

・comments
・favoite_comments(中間テーブル)
 -comment_id
 -user_id
・users

Model

comment.rb
has_many :favorite_comments
has_many :favo_users, class_name: "User", foreign_key: "user_id", through: :favorite_comments, :source 'user', dependent: :delete_all
user.rb
has_many :favorite_comments
has_many :favo_comments, class_name: "Comment", foreign_key: "comment_id", through: :favorite_comemnts, :source 'user', dependent: :delete_all
favorite_comment.rb
belogns_to :comment
belongs_to :user

フォロー機能

ユーザー(from_user)がユーザー(to_user)をフォローする

テーブル

・users
・follow_users(中間テーブル)
-to_user_id
-from_user_id

Model

user.rb
has_many :follow_users_of_to_user, class_name: 'FollowUser', foreign_key: 'to_user_id', dependent: :delete_all
has_many :friends_of_to_user, through: :follow_users_to_user, source: 'from_user'

has_many :follow_users_of_from_user, class_name: 'FollowUser', foreign_key: 'from_user_id', dependent: :delete_all
has_many :friends_of_from_user, through: :follow_users_from_user, source: 'to_user'
follow_user.rb
belongs_to :to_user, class_name: 'User', foreign_key: 'to_user_id'
belongs_to :from_user, class_name: 'User', foreign_key: 'from_user_id'

associationのoptionについて

dependent

今回はdependent: :delete_allを使ったが、
時としてこんなエラーになることがある。

Cannot delete or update a parent row: a foreign key constraint fails (`finc_blog_development`.`comments`, CONSTRAINT `fk_rails_35f401eaf6` FOREIGN KEY (`article_id`) REFERENCES `articles` (`id`))

user削除->article削除->comment削除と2段階以上の関連があることが問題だった。
2段階以上の関連があるときは:destroyを使わなければならない。
ただし、1段階の関連のときは、処理速度の速いdelete_allのほうが効率がよい。

つまり、
1段階の関連だけなら処理は速いdelete_allで2段階以上の関連ならdestroyを使えばよい。

through

多対多のモデルで中間テーブルを使うときに登場し、中間テーブルを意識せずに関連データの取得ができるようになる。
has_and_belongs_to_manyを使う方法もあるが、制約が多いのでthroughを使うほうが無難。

class_name, foreign_key, source

多対多の場合、フォロー機能のようにUserモデルだけでフォローする側、フォローされる側の両方の役割を担う必要があり、その関係を示すために使用している。

参考

Railsで多対多のテーブルを実装する
同一モデル間で友達関係のような多対多関連をつくる【rails4】

58
60
0

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
58
60