1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】混乱しがちなアソシエーションのclass_nameやforeign_keyを理解する

Last updated at Posted at 2020-11-17

Railsでお知らせ機能やフォロー機能を実装しているとclass_nameやforeign_keyが出てくると思います。これらを理解するのに時間がかかったので、備忘録もかねて投稿します。

今回はお知らせ機能を例に挙げる。
イメージしやすいようER図を載せる。(最低限のカラムしか書いてません。)

お知らせ機能ER図.png

お知らせ機能を実装していると@user.passive_notificationsのようにして自分に来ている通知のレコードをまとめて取得したいことがある。そういう場合、下のように書く。

user.rb
has_many :passive_notifications, class_name: "Notification", foreign_key: "visited_id"

少し複雑なので、簡単な例を挙げる。

Userモデルで下記のように定義した場合

よく使うhas_many :tweetsは実は色々省略されている。

user.rb
has_many :tweets

# 同じ意味
has_many :tweets, class_name: "Tweets", foreign_key: "user_id"

Railsで開発をするとhas_manyやbelongs_toを使ってモデルでリレーションを組むが、これを書くことによって、Userクラスへのticketsメソッドの定義が裏で行われている。例でいうと、ticketsメソッドの対象となるClassはTweetクラスで、ticketsテーブルのuser_idの値を参照してレコードを取得する。

Railsの規則によりモデルの複数形でメソッドを定義する場合、クラス名、外部キーを省略することができる。なぜならメソッド名により暗黙的にクラス名、外部キーが決定されるからである。

上記のようにメソッドを定義する(リレーションを組む)ことで、コントローラーなどで下のメソッドが使えるようになる。

user.rb
@user = User.find(params[:id])
@user.tweets

少し脱線したが、このことを頭に入れてお知らせ機能のリレーションをもう一度見てみる。

user.rb
has_many :passive_notifications, class_name: "Notification", foreign_key: "visited_id"

ここの記述では、Userモデルにpassive_notificationsメソッドを定義している。
メソッド名からはクラス名が不明なため、class_name: "Notification"として対象のクラスを明示している。また、外部キーを設定しない場合、notificationsテーブルからuser_idのカラムを探しにいってしまうため、foreign_key: "visited_id"として定義する。

これにより、@userのidとnotificationsテーブルのvisited_idとが一致したレコード、つまり@user宛の通知のレコードがまとめて取得できるようになる。

user.rb
@user = User.find(params[:id])
@user.passive_notifications #ユーザ宛の通知のレコードを全件取得

以上です。
まちがっていたらご指摘お願いします。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?