ステータスフィールド
現在のユーザーにフォローされているユーザーのマイクロポストの配列を作成し、現在のユーザー自身のマイクロポストと合わせて表示します。
このセクションを通して、複雑さを増したフィードの実装に進んでいきます。
これを実現するためには、RailsとRubyの高度な機能の他に、SQLプログラミングの技術も必要です。
動機と計画
ステータスフィードのテスト
test/models/user_test.rb
require 'test_helper'
.
.
.
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
テスト
ubuntu:~/environment/sample_app (following-users) $ rails t
Running via Spring preloader in process 5728
Started with run options --seed 13331
FAIL["test_feed_should_have_the_right_posts", #<Minitest::Reporters::Suite:0x000056391fee5aa8 @name="UserTest">, 3.5545889589998296]
test_feed_should_have_the_right_posts#UserTest (3.56s)
Expected false to be truthy.
test/models/user_test.rb:131:in `block (2 levels) in <class:UserTest>'
test/models/user_test.rb:129:in `block in <class:UserTest>'
74/74: [===========================] 100% Time: 00:00:04, Time: 00:00:04
Finished in 4.55511s
74 tests, 341 assertions, 1 failures, 0 errors, 0 skips
Expected false to be truthy.
とりあえず動くフィードの実装
app/models/user.rb
テスト
ubuntu:~/environment/sample_app (following-users) $ rails t
Running via Spring preloader in process 7499
Started with run options --seed 53450
74/74: [===========================] 100% Time: 00:00:04, Time: 00:00:04
Finished in 4.11729s
74 tests, 378 assertions, 0 failures, 0 errors, 0 skips
演習
リスト 14.44において、現在のユーザー自身の投稿を含めないようにするにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか?
リスト 14.44において、フォローしているユーザーの投稿を含めないようにするにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか?
リスト 14.44において、フォローしていないユーザーの投稿を含めるためにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか? ヒント: 自分自身とフォローしているユーザー、そしてそれ以外という集合は、いったいどういった集合を表すのか考えてみてください。
サブセレクト
whereメソッド内の変数に、キーと値のペアを使う
app/models/user.rb
class User < ApplicationRecord
.
.
.
# 試作feedの定義
# 完全な実装は次章の「ユーザーをフォローする」を参照
def feed
# すべてのユーザーがフィードを持つので、feedメソッドはUserモデルで作るのが自然です
Micropost.where("user_id IN (:following_ids) OR user_id = :user_id",
following_ids: following_ids, user_id: id) # following_ids フォローのユーザーidを取得
# id 要素
# whereメソッド テーブル内の条件に一致したレコードを配列の形で取得することができるメソッド
# user_idを条件として取得することができる。
# 上の疑問符があることで、SQLクエリに代入する前にidがエスケープされるため
# 、SQLインジェクションと呼ばれる深刻なセキュリティホールを避けることができます。
# SQL文に変数を代入する場合は常にエスケープする習慣をぜひ身につけてください。
end
.
.
.
end
フィードの最終的な実装
app/models/user.rb
class User < ApplicationRecord
.
.
.
# 試作feedの定義
# 完全な実装は次章の「ユーザーをフォローする」を参照
def feed
# すべてのユーザーがフィードを持つので、feedメソッドはUserモデルで作るのが自然です
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)
# following_ids フォローのユーザーidを取得
# id 要素
# whereメソッド テーブル内の条件に一致したレコードを配列の形で取得することができるメソッド
# user_idを条件として取得することができる。
# 上の疑問符があることで、SQLクエリに代入する前にidがエスケープされるため
# 、SQLインジェクションと呼ばれる深刻なセキュリティホールを避けることができます。
# SQL文に変数を代入する場合は常にエスケープする習慣をぜひ身につけてください。
end
.
.
.
end
テスト
ubuntu:~/environment/sample_app (following-users) $ rails t
Running via Spring preloader in process 10510
Started with run options --seed 15480
74/74: [===========================] 100% Time: 00:00:04, Time: 00:00:04
Finished in 4.25870s
74 tests, 378 assertions, 0 failures, 0 errors, 0 skips