2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】ステータスフィード【Rails Tutorial 14章まとめ】

Posted at

##ステータスフィード
自身のマイクロポストと、フォローしているユーザーのマイクロポストを表示するフィードを実装する。

###フィードの条件とテスト
フィードが満たす条件は以下の3つである。
①フォローしているユーザーのマイクロポストを含む
②自身のマイクロポストを含む
③フォローしていないユーザーのマイクロポストを含まない
これらを満たすように、まずテストを書く。

test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  .
  .
  .
  test "feed should have the right posts" do
    michael = users(:michael)
    archer  = users(:archer)
    lana    = users(:lana)
    # フォローしているユーザーの投稿を確認
    lana.microposts.each do |post_following|
      assert michael.feed.include?(post_following)
    end
    # 自分自身の投稿を確認
    michael.microposts.each do |post_self|
      assert michael.feed.include?(post_self)
    end
    # フォローしていないユーザーの投稿を確認
    archer.microposts.each do |post_unfollowed|
      assert_not michael.feed.include?(post_unfollowed)
    end
  end
end

Michaelはarcherをフォローしており、lanaをフォローしていない設定である。

###フィードの実装
条件を満たすフィードの実装には、自身のIDまたはフォローしているユーザーのIDに対応するuser_idを持つマイクロポストを取得する必要がある。
試作フィードでは自身のマイクロポストのみを表示していたので、feedメソッドは以下のようだった。

app/models/user.rb
  # 試作feedの定義
  def feed
    Micropost.where("user_id = ?", id)
  end

フォローしているユーザーのマイクロポストを取得するために、まずフォローしているユーザーのIDを配列の形で取得する。
そのためには、following_idsメソッドを使う。

>> User.first.following_ids
=> [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51]

following_idsメソッドは、has_many :followingの関連付けをした時に自動で生成される。

feedメソッドでこれを使うためには、SQLを使って以下のようにする。

app/models/user.rb
  # ユーザーのステータスフィードを返す
  def feed
    Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id)
  end

これでテストがGREENになる。

###サブセレクトとフィードの改良
ここまでで実装したフィードではフォロー数が膨大になるとアプリケーションの動作が遅くなる。
フォローしているユーザーのIDをデータベースから取得した後、それを使ってまたデータベースからマイクロポストを取得するという操作をしていることが原因である。
この問題をSQLのサブセレクトを使用することで解決する。

まずfeedメソッドを少し書き換える。

app/models/user.rb
  # ユーザーのステータスフィードを返す
  def feed
    Micropost.where("user_id IN (:following_ids) OR user_id = :user_id", following_ids: following_ids, user_id: id)
  end

このコードでは、変更前のコードで?に代入されていた部分がハッシュのキーと値に変わっている。
?にはキーが入っている。
これは同じ変数を複数の箇所で使用するためである。

次にfollowing_idsを以下のようなSQLの文字列で置き換える。

following_ids = "SELECT followed_id FROM relationships
                 WHERE  follower_id = :user_id"

user_idが1の場合、このコードは「ユーザー1がフォローしているユーザーすべてを選択する」という意味を持つ。
これによりフォローしているユーザーをIDを経由せずに直接データベースから取得できるため、動作を高速化できる。

app/models/user.rb
  # ユーザーのステータスフィードを返す
  def feed
    following_ids = "SELECT followed_id FROM relationships
                     WHERE follower_id = :user_id"
    Micropost.where("user_id IN (#{following_ids})
                     OR user_id = :user_id", user_id: id)
  end

following_idsにはSQLの文字列が入っているので、式展開を使っている。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?