Rails 総復習1ヶ月チャレンジ 9日目(Railsチュートリアル編)

本日は9日目です!なんだかんだで1週間以上かかる濃い内容だったRailsチュートリアルも今日で最後です!
ではやっていきます!

9日目(Ruby on Rails チュートリアル 14章ユーザーをフォローする)   

第14章はユーザーが気に入った他のユーザーをフォローすることができる機能を実装するものです。フォローできるということは他のユーザーからフォローされるということも考えなければなりません。この章で一番重要なのではテーブルをどのように考えるかです。(自分が苦手な部分です)これにはフォローする、フォローされるというところを切り分けて考えると良さそうです。

フォローする、解除する関係について

今までマイクロポストを作成、削除などリソースに関連したことから

あるユーザーが別のユーザーをフォローする(◯◯を作成)、あるユーザーが別のユーザーのフォロー解除をする(◯◯を削除)

◯◯の部分を考える必要があります。
これを考えると2人のユーザーの「関係(リレーションシップ)」と考えるとしっくりきます。したがってユーザー間の関係性を示すRelationshipモデルを作成すれば良さそうです。

自分がフォローする側(能動的な部分)の考え方(active_relationships)

https://i.gyazo.com/fb96b9a885bd5ccb92e98840bbff760e.png (Railsチュートリアル スライド : 第14章 ユーザーをフォローするより引用)

実装

$ rails generate model Relationship follower_id:integer followed_id:integer
#db/migrate/[timestamp]_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[6.0]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :followed_id

      t.timestamps
    end
    add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    add_index :relationships, [:follower_id, :followed_id], unique: true
  end
end

データベースに問い合わせした時に、よく使うデータは高速化させることができる。 フォローしている数 フォロワーの数 複合キーインデックス(複数のカラムで検索)→follower_idとfollowed_idの組み合わせが必ずユニークであることを保証する仕組みです。これにより、あるユーザーが同じユーザーを2回以上フォローすることを防ぎます。

  • referencesが使えない理由

"{モデル名}_id"のようになり、規約に乗っ取っていない、follwer, followedクラスがある前提で作られてしまう

  • Userモデルのアソシエーション
class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
   #デフォルトで設定されている class_name: "Micropost"
   #デフォルトで設定されている foreign_key: "user_id"
  has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
:
end

今回は参照するclassと、外部キーを自分で設定する必要があります。class_name: "Relationship"とforeign_key: "follower_id"部分がその設定の記述です。

  • Relationshipモデル
class Relationship < ApplicationRecord
  belongs_to :follower, class_name: "User"
  #followerというclassは存在しない為にclass_name: "User"の記述が必要
  belongs_to :followed, class_name: "User"
  #followedというclassは存在しない為にclass_name: "User"の記述が必要
end
  • Userモデルにフォローしたユーザーの集合を取得するメソッド(following)を記載
class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  #デフォルトで設定されている class_name: "Micropost"
  #デフォルトで設定されている foreign_key: "user_id"
  has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
  has_many :following, through: :active_relationships, source: :followed
:
end

この部分

 has_many :following, through: :active_relationships, source: :followed

これは下記を簡潔に使えるようにしています。

@user.active_relationships.map(&:followed)

簡潔に使えるようになる。

@user.following

ここでは
has_manyで新しくfollowingというメソッドを宣言。
followingメソッドの役割は、Userクラスのインスタンスオブジェクトに対してactive_relationshipsメソッドを呼び出し、その返ってきたデータの集合に対してfollowedメソッドを一つずつ実行します。これでフォロワーがフォローされている側の情報を取得できます。

次にフォロワーを考える (受動的、passive_relationships)

https://i.gyazo.com/c5f871f12e212add7d686481eddab7cd.png (Railsチュートリアル スライド : 第14章 ユーザーをフォローするより引用)   

実装(Relationshipsモデルはactive_relationshipsの際に実装済み)

    • Userモデルのアソシエーション
class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  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
  .
  .
  .
end

ここの流れは、
has_manyで新しくfollowersというメソッドを宣言。
followersメソッドの役割は、Userクラスのインスタンスオブジェクトに対してpassive_relationshipsメソッドを呼び出し、その返ってきたデータの集合に対してfollowerメソッドを一つずつ実行します。これでフォローされている側がフォロワーの情報を取得できます。

「||=」とは何か?

フォロワーの統計情報を表示するパーシャルで下記のような表記がありました。

<% @user ||= current_user %>

これは元々下記のコードを短縮したものです。

<% @user = @user || current_user %>  

Rubyでは、||演算子をいくつも連続して式の中で使う場合、項を左から順に評価し、最初にtrueになった時点で処理を終えるように設計されています。nilは論理値はfalseです。
今回の場合、パーシャルを呼び出すのはHomeページとUser詳細ページなので、Homeページでパーシャルを呼び出した場合は@userはnilとなるので代わりにcurrent_userが代入されます。User詳細ページの場合、@userはnilではないので何も代入されません。

今回は以上です!明日からはスクール課題の復習編です!