has_many,throughとかでモデルやテーブルの構成を考えるとき,どうしてもカラム名と関連づけるテーブルの名前が一致しなかったり,望み通りの命名で行けない場合がある.
もちろん,一つのテーブルが,他のテーブルのレコードを複数持つだけなら,命名はスマートに決められるのだけれど.
今回の例題は,Userモデルに対するフォロー・フォロワーを実現すること.
Userは一つのテーブルでなければならないことはわかりますよね.
ということは,UserテーブルがUserFollowという中間テーブルを介して,Userテーブルのレコードをhas_manyするという形をとる.
もうガリガリと書いていきます.
まず,こういう,元から名前の統一が難しそうな場合はテーブルを先に作ってしまう.
Userテーブル
id | name |
---|---|
1 | poteto |
2 | hoge |
UserFollowテーブル
id | user_id | follow_id |
---|---|---|
1 | 1 | 2 |
これで,potetoさんがhogeさんをフォローしているという状態が実現できる.
続いてモデルの定義.
user.rb
class User < ActiveRecord::Base has_many :user_follows, class_name: "UserFollow", foreign_key: :user_id has_many :follows, through: :user_follows has_many :user_followers, class_name: "UserFollow", foreign_key: :follow_id has_many :followers, through: :user_followers end
user_follow.rb
class UserFollow < ActiveRecord::Base belongs_to :follow, class_name: "User", foreign_key: follow_id belongs_to :follower, class_name: "USer", foreign_key: user_id end
こんな感じになりますよね.
class_nameは対象となるモデルを指定して,foreign_keyで,どのカラムの値が一致するレコードを取得するのかを指定します.
user_followsに関して言うなら,あるuserのid値が,UserFollowのuser_idカラムの値と一致するレコードを取り出します.
followsに関しては,そのuser_followsをthroughするわけですね.
ではfollowsはどこで指定されるのか?
UserFollowの定義で指定されます.
belongs_to :follow, class_name: "User", foreign_key: follow_id
このようにして,今度は,選択されたUserFollowのレコードのfollow_idの値が,class_nameで指定されたUserテーブルのid値と一致する,Userテーブルのレコードを,followとして抜き出します.
Userモデルはそれをhas_manyするのでfollowsという複数形になっているわけです.
逆向き(followers)も同様ですね.
この辺を上手く使いこなすと,いい感じに多対多の関連を作ることができます.