Ruby
Rails
Railsチュートリアル

Railsチュートリアル第14章でアホみたいにハマった独学者の備忘録

Railsチュートリアル第14章の 14.1.5 フォロワーの演題で盛大にハマったので備忘録を残します。

14章でどんなことを勉強するのか

Railsチュートリアルでは、Twitteサービスのクローンを作っています。
第14章では、Twtterでいうところのfollowとfollowerの機能を実装しながら勉強します。

どんなところではまったのか

フォローするユーザーとフォローされるユーザーを記録するために、
この章で扱うデータモデルの構成は、以下に示すような関係になっていました。

Userテーブル

id name email
1 foo bar@bar.com

↓ userテーブルのidとfollower_idをthroughで紐づけ

follower_id followed_id
:kissing_closed_eyes: 1 2
:kissing_closed_eyes: 1 3
3 2
5 2
:kissing_closed_eyes: 1 6
2 2

↓ followed_idでuser.followingという配列を作成する
:has_many

id name email
→2 ... ...
id name email
→3 ... ...
id name email
→6 ... ...

コードで表すと

app/models/user.rb
  has_many :active_relationships,  class_name:  "Relationship",
                                   foreign_key: "follower_id",
                                   dependent:   :destroy
  has_many :passive_relationships, class_name:  "Relationship",
                                   foreign_key: "followed_id",
                                   dependent:   :destroy
  has_many :following, through: :active_relationships,  source: :followed
  has_many :followers, through: :passive_relationships, source: :follower

上記の記述により、様々なメソッドが使えるようになります。

active_relationship.follower フォロワーを返します
active_relationship.followed フォローしているユーザーを返します
user.active_relationships.create(followed_id: other_user.id) userと紐付けて能動的関係を作成/登録する
user.active_relationships.create!(followed_id: other_user.id) userを紐付けて能動的関係を作成/登録する (失敗時にエラーを出力)
user.active_relationships.build(followed_id: other_user.id) userと紐付けた新しいRelationshipオブジェクトを返す

Railsが作ってくれたメソッドに加えて、チュートリアルでは以下のようなメソッドも定義しました。

app/models/user.rb
class User < ApplicationRecord
  .
  .
  .
  def feed
    .
    .
    .
  end

  # ユーザーをフォローする
  def follow(other_user)
    following << other_user
  end

  # ユーザーをフォロー解除する
  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id).destroy
  end

  # 現在のユーザーがフォローしてたらtrueを返す
  def following?(other_user)
    following.include?(other_user)
  end

  private
  .
  .
  .
end

演習課題は?

やっとここまでこれました。以下問題文。

コンソールを開き、何人かのユーザーが最初のユーザーをフォローしている状況を作ってみてください。最初のユーザーをuserとすると、user.followers.map(&:id)の値はどのようになっているでしょうか?

1.コンソール開いて、適当な変数名(user1, user2, user3)にUserテーブルの適当な値(User.firstとか)を代入
2.user2.follow(user1)でもいいし、railsがつくった user1.active_relationships.create(user2)でもいいからフォローとフォロワーを作成
3.user1.followers.map(&:id)でfollowerになったuserのidを配列で出力

できない...。

** 原因 **
follower_idとRelationテーブルのヒモ付を間違えてた。
正しいコードは

app/models/user.rb
  has_many :passive_relationships, class_name:  "Relationship",
                                   foreign_key: "followed_id",
                                   dependent:   :destroy

  has_many :followers, through: :passive_relationships, source: :follower

間違えたコード has_many の through: にactive_relationships渡してる...

app/models/user.rb
  has_many :passive_relationships, class_name:  "Relationship",
                                   foreign_key: "followed_id",
                                   dependent:   :destroy

  has_many :followers, through: :active_relationships, source: :follower

解決まで時間かかりました。コードのミスって治すのが本当に難しいですね...
followメソッドが悪いのかな?user.active_relationships.createならいけるかも!とか
コンソールで試行錯誤したらこんな落ちでしたとさ!
Railsチュートリアル同じようにつまった人いたらこれが参考になりますように!