find_or_create_byメソッド
def follow(other_user)
unless self == other_user #フォローしようとしてるother_userが自分ではないか検証
self.relationships.find_or_create_by(follow_id: other_user.id)
end
end
引数の条件に該当するデータがあればそれを返すfind_by(other_user)
、なければ新規作成create(other_user)
新規作成後、保存する
参考記事:find_or_initialize_byとfind_or_create_byの違いとは?
includesメソッド
def following?(other_user)
self.followings.include?(other_user)
end
include?メソッドとは?
引数で指定した要素が配列中に含まれてるか判定するメソッド
※selfはuser自身なのでuser。
self(自分自身)がfollowing(フォローしてる人たち)の中でother_userが含まれてるかどうか判定するってこと。
other_userが含まれていればtrueを返し、含まれてなければfalseを返す。
relationshipモデルのマイグレーションファイル
class CreateRelationships < ActiveRecord::Migration[5.2]
def change
create_table :relationships do |t|
t.integer :follower_id
t.integer :following_id
t.timestamps null: false
add_index :relationships, :follower_id
add_index :relationships, :following_id
add_index :relationships, [:follower_id, :follwing_id], unique: true #follow_idとfollowing_idの同じ組み合わせができないようにする設定
end
end
end
add_index
がindexをつけることくらいはわかるが、そもそもindexって何のためにつけるんだっけ?
add_index
の記述の箇所の意味がわからないということでこちらの記事が参考になった。
参考記事:データベースにindexを貼る方法
Q.indexは何のためにつける?
カラムからデータを取得するときに検索しやすいようにするため。例えば今回だったらfollowerカラムからfollwerを検索しやすいようにするため。データが3人だけとかならいらないけど、1万人とかになってくると検索するのに時間がかかるのでつけた方がいいってことみたい。
add_index :テーブル名, カラム名
上の例でいうと、relationテーブルのfollow_idカラム、relationテーブルのfollowing_idカラムってことになる。
userモデルの書き方
has_many :follwing_relationships, foreign_key: "follower_id", class_name: "Relationship", dependent: :destroy
follwing_relationships
モデルは実際には存在しない。あくまで便宜上こういうふうに設定してるだけ。このモデルはフォローしてる人たちのモデル。
なのでfollower_id
が外部キーで設定されてる。
class_name: "Relationship"
これはさっきも言ったけど、follwing_relationships
モデルは実際には存在しなくて、実際に存在するのは"Relationship"モデルだから、名前はfollwing_relationships
ってなってるけど、名前だけで本当は"Relationship"のことだよ〜と言ってる。
dependent: :destroy
これは結構単純で、あるuserが無くなったら、そのuserがフォローしてる人たちとのrelationも消えるようにする設定。userモデルとrelationshipモデルは従属関係にあって、userが消えると、そのuserのrelationship(userとfollow_idsの関係)も消えるということ。
has_many :follwings, through: :following_relationships
has_many :follwings(モデル名)
でモデル間のアソシエーションを定義してる。through: :following_relationships
これは中間テーブルを示してる。何度か出てきてるけど、名前はfollowing_relationships
だけど実際はrelationships
が中間テーブル。
要は、userモデル(フォローされてる人たち)とuserモデル(フォローしてる人たち)という2つのuserモデルの中間にrelationモデルがあるってこと。
アソシエーションを利用するための2つの条件
- モデルクラスにhas_manyやbelongs_toなどのメソッドで関係が定義されている
- 所属する側のテーブルに所属するモデル名_idというカラムがある
特に2.は忘れがちなので注意!!
今回だと、following_idが必要ということだけど、上記のマイグレーションファイルのところ見てもらうと、あそこでfollowing_idを入れてあるのがわかると思うけど、今回はそこで定義してるからOK。
def following?(other_user)
following_relationships.find_by(following_id: other_user.id)
end
def follow!(other_user)
following_relationships.create!(following_id: other_user.id)
end
def unfollow!(other_user)
following_relationships.find_by(following_id: other_user.id).destroy
end
find_by
メソッドは1件しか返さない。なので、これを設定しておけば、ピンポイントで探したいuserを探せる。
参考記事:【Rails】世界で一番詳しいfind_byメソッドのいろいろな使い方
create!
はそのまま保存するって意味。
最後のは1件userを見つけてきて、.destroy
メソッドは消すだからそのデータを消すってこと。
僕がまだよく理解できてないのが、なぜモデルにメソッドを書くのか?
普通こういうメソッドはcontrollerに書くものと思ってたけど。
探したらこんな記事見つけた。
Railsのモデルに書いたメソッドってどうやってコントローラで使うの?
それでわかったのが、controllerの記述を出来るだけシンプルにするため。ってことみたい。
確かに上記の記述をcontrollerに書いたらごちゃごちゃしててわかりづらくなりそうだ。
マイグレショーンファイルのエラー
Caused by:Mysql2::Error: Table '(アプリ名)_development.relationships' doesn't exist
「マイグレーション Table doesn't exist」で検索してみたら、この記事が出てきた。
参考記事:Rails5.1に移行後のmigrationファイルの注意
ルーティング
resources :users do
member do
get :following, :followers
end
end
Q.member
って何?どういう意味?
参考記事:railsのroutes.rbのmemberとcollectionの違いをわかりやすく解説してみた。〜rails初心者から中級者へ〜
following_user GET /users/:id/following(.:format) users#following
followers_user GET /users/:id/followers(.:format) users#followers
URLを見てもらうとわかるように、:idが自動で追加されるようになる。
relationshipモデルのidが空になってるというエラー
has_many :following_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
def following?(other_user)
following_relationships.find_by(following_id: other_user.id)
end
following_relationshipsはRelationshipモデルを指してる。
following?メソッドはother_userという1人のユーザーを引数にとり、フォローする相手のユーザーがデータベース上に存在するかどうかをチェックする。
今回のエラーは、フォローする相手のuserのidが定義されていなくて空になってるよというエラー。
参考にさせて頂いた記事
railsでフォロー機能をつける。
この記事を見ながらフォロー機能を実装しました。
データベースにindexを貼る方法
find_or_initialize_byとfind_or_create_byの違いとは?
Railsのモデルに書いたメソッドってどうやってコントローラで使うの?