Railsチュートリアル

Rails チュートリアル メモ 第13章

メモ

14.1.1 データモデルの設計

  • 関係性を表現するために、1つのテーブルを用意する。
  • テーブルには follower_id と followed_id というカラムがある。
  • 「ユーザー 1 がユーザー 2 をフォローする」とは、このテーブルに「follower_id: 1, followed_id: 2」というカラムが1行追加される、ということである。

という設計。シンプルで素晴らしい。

14.1.2 やりたいこと

  • Relationship のインスタンスを r とすると

    • r.follower で、フォロー元のユーザーの id を返す
    • r.followed で、フォロー先のユーザーの id を返す
  • User のインスタンスを u とすると、

    • u.active_relationships.create(または build)すると、あらかじめ follower_id に u.id がセットされた状態で Relationship のインスタンスを保存(または 作成)する

上記における課題は、属性名とクラス名が異なる点。例えば Micropost の場合は、micropost.user というメソッドで、その micropost を所有する User を取得できた(属性名とクラスが一致している)。しかし、今回は r.follower というメソッドで、(Follower ではなく)User を取得できる必要がある。User 目線でも、u.active_relationships で(ActiveRelation ではなく)Relationships を扱える必要がある。

そこで、以下のような定義をする。

class Relationship < ApplicationRecord
  belongs_to :follower, class_name: 'User'
end
  • r.follower のように呼び出すけど、その follower の実体は User クラスだよ

といった設定をしている。同様に User 側についても、

class User < ApplicationRecord
  has_many :active_relationships, {
             class_name: "Relationship",
             foreign_key: "follower_id",
             dependent: :destroy
           }
  • user.active_relationships のように呼び出すけど、その実体は Relationship クラスだよ
  • Relationship クラスの follower_id と外部キーで結びつくよ
    • 所有側で設定することに注意

といった設定をしている。

14.2.2 member

  resources :users do
    member do
      get :following, :followers
    end
  end

こんなルーティングを定義すると、/users/1/following/ のようなルートが有効になる。対応するアクションは users#following 。

14.2.5 Ajax

  • form_for に remote: true オプションを追加することで、Ajax が使われるようになる
  • コントローラ側で respond_to を使うと、要求されたフォーマットごとに何を返すかを決められる
    • 書式がわかりづらいので注意。case 文だと思ってしまうと楽
  • 例えば user#show アクションの場合、フォーマットが html なら view/user/show.html.erb が描画に使われる。そのアナロジーで、フォーマットが js の場合は view/user/show.js.erb がブラウザで評価される。

それ以外のことはよくわからん・・・。

14.3.3 サブセレクト

適当にコードを書くと、

  • フォローしているユーザー達の ID を取得するのに SELECT 1回
  • それらの ID それぞれに対して microposts を取得するのに SELECT 1回

が発生してしまい、数が増えたときに重くなる。そこで、サブクエリを使って1回の問い合わせで済むようにする。

せっかく ActiveRecord がいろいろやってくれるのに、パフォーマンスを考えると結局 SQL 書かなきゃいけないのか・・・。