らくだ🐫にもできるRailsチュートリアル|14.3

14.3 ステータスフィード

ステータスフィードを実装する!
→フォローされているユーザーのマイクロポストとログイン中のユーザーのマイクロポストを合わせて表示する
見本はこちら→RoRT本文参照

14.3.1 動機と計画

現在のユーザーによってフォローされているユーザーに対応するユーザーidを持つマイクロポストを取り出し、同時に現在のユーザー自身のマイクロポストも一緒に取り出すことです。


テストの方が明確な雰囲気なのでテストから書いていく(テスト駆動開発!)

フィードのテスト

  1. フォローしているユーザーのマイクロポストがフィードに含まれている
  2. 自分自身のマイクロポストもフィードに含まれている
  3. フォローしていないユーザーのマイクロポストがフィードに含まれていない

上記3つの条件を満たすテストを定義していく

feedに何も定義していないのでテストはRED

演習

  1. マイクロポストのidが正しく並んでいると仮定して (すなわち若いidの投稿ほど古くなる前提で)、図 14.22のデータセットでuser.feed.map(&:id)を実行すると、どのような結果が表示されるでしょうか? 考えてみてください。ヒント: 13.1.4で実装したdefault_scopeを思い出してください。

user.feedのidを配列にして取り出す→[1,2,4,5,7,9,10]
投稿日時が古い順に並んでしまう

14.3.2 フィードを初めて実装する

ステータスフィードに対する要件定義はリスト 14.42のテストで明確になったので (つまりこのテストにパスすれば良いので)、早速フィードの実装に着手してみましょう。

要件定義 #とは
最終的な形は込み入っているのでパーツ毎に確認しつつ導入していくとの事。

フィードで必要なクエリ

micropostsテーブルから、あるユーザー (つまり自分自身) がフォローしているユーザーに対応するidを持つマイクロポストをすべて選択 (select) することです。

これをコードにするとこう↓

<>は例えの証でコードの一部じゃないんだって🐫
13.3.3でプロトタイプを作成した際は
現在のユーザーに対するユーザーidを持つマイクロポストを選択したけど

今回はもう少し複雑になる
例えばこう↓

(following_idsについては読み進めればわかる🐫よくあるパターン)
これらの条件から、フォローされているユーザーに対するidの配列が必要であることがわかる
→mapメソッドで実装可能!

このメソッドはすべての「列挙可能 (enumerable)」なオブジェクト (配列やハッシュなど、要素の集合で構成されるあらゆるオブジェクト) で使えます

例えばこんな事も

これによりuser.followingにある各要素のidを呼び出して、フォローしているユーザーのidを配列として扱うことができる
例えばこんな感じ

これはとても便利なのでActive Recordでは次のようなメソッドも用意されている

このfollowing_idsメソッドは、has_many :followingの関連付けをしたときにActive Recordが自動生成したものです (リスト 14.8)。これにより、user.followingコレクションに対応するidを得るためには、関連付けの名前の末尾に_idsを付け足すだけで済みます

結果、フォローしているユーザーidの文字列を取得するにはこう

なんだけど、
実際はRailsがよしなにやってくれるのでfollowing_idsメソッドを使えばOK

実装するとこう↓

いくつかのアプリケーションにおいては、この初期実装だけで目的が達成され、十分に思えるかもしれません。しかしリスト 14.44にはまだ足りないものがあります。それが何なのか、次に進む前に考えてみてください (ヒント: フォローしているユーザーが5,000人もいたらどうなるでしょうか?)。

→読み込みデータが多すぎて重たくなる?(?

演習

  1. リスト 14.44において、現在のユーザー自身の投稿を含めないようにするにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか?
  2. リスト 14.44において、フォローしているユーザーの投稿を含めないようにするにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか?
  3. リスト 14.44において、フォローしていないユーザーの投稿を含めるためにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか? ヒント: 自分自身とフォローしているユーザー、そしてそれ以外という集合は、いったいどういった集合を表すのか考えてみてください。

1.

2.

3.

14.3.3 サブセレクト

現在のフィードの設計では投稿されたマイクロポストの数が膨大になったときにWebサービス全体が遅くなるなどの弊害があるなどする。

14.3.2で示したコードの問題点は、following_idsでフォローしているすべてのユーザーをデータベースに問い合わせし、さらに、フォローしているユーザーの完全な配列を作るために再度データベースに問い合わせしている点です

もっと効率的なコードに置き換える→SQLのサブセレクト (subselect) を使うことで解決できる!!

サブセレクトとは何ぞ

わからないので調べたのだけど、
サブセレクトとサブクエリがごっちゃになって良くわかりません!ってなったので
にゅ〜ぶる会で質問したところ

サブクエリは、入れ子になってる子供のクエリの事。
サブセレクトは、入れ子になったセレクト文全体の事。
かな?

と、教えてもらいましてスッキリ感(いつもありがとうございますだねぇ🐫)
というわけでやっていく。

同じ変数を複数の場所に挿入したい場合はプレースホルダー(?)ではなくハッシュで置き換えるほうが便利
ハッシュ形式で記述しておいてもSQLインジェクションを防げる!

コードの解説はこう↓

このサブセレクトは集合のロジックを (Railsではなく) データベース内に保存するので、より効率的にデータを取得することができます。

これを実際のコードに落としこむとこう↓

※「following_ids」という文字列はエスケープされているのではなく、見やすさを重視して式展開の形にしている

もちろん、サブセレクトを使えばいくらでもスケールできるなどということはありません。大規模なWebサービスでは、バックグラウンド処理を使ってフィードを非同期で生成するなどのさらなる改善が必要でしょう。ただし、Webサービスをスケールさせる技術は非常に高度かつデリケートな問題なので、本書ではここまでの改善で止めておきます。

これにて完全なフィードが実装できた!!

いつもの流れでGitHubにpushとherokuにデプロイ!!

演習

  1. Homeページで表示される1ページ目のフィードに対して、統合テストを書いてみましょう。リスト 14.49はそのテンプレートです。
  2. リスト 14.49のコードでは、期待されるHTMLをCGI.escapeHTMLメソッドでエスケープしています (このメソッドは11.2.3で扱ったCGI.escapeと同じ用途です)。このコードでは、なぜHTMLをエスケープさせる必要があったのでしょうか? 考えてみてください。ヒント: 試しにエスケープ処理を外して、得られるHTMLの内容を注意深く調べてください。マイクロポストの内容が何かおかしいはずです。また、ターミナルの検索機能 (Cmd-FもしくはCtrl-F) を使って「sorry」を探すと原因の究明に役立つはずです。

1.

2.
エスケープしないと記号が特殊文字で出力されてしまうため

feedメソッドをリファクタリング

記事を書きあがって添削していただいた際に
「feedメソッドってこれで完成形じゃないよね?」というお話がありまして。
現状だと書かれているのはSQL文なんですね。
と、いう訳で考えました。


この辺を参考に、まずはフォローしている人のmicropostを取り出す方法を考える

自身の投稿も含まれるようにする

テストも通って良い感じにできたっぽい!
チェックしてもらうと、更にこんな形を教えていただきました!
よりすっきり!!

14.4 最後に

まとめにつき割愛
機能拡張も割愛
ただ、I18nを使っての日本語化は随時やってましたです
あとはローカル環境を作ってテンプレートをslim&Sassで書いてみようと思っています。練習。

まとめとか感想

さあ!
これにてらくだ🐫にもできるRailsチュートリアルのまとめ、終了です!!
ブログにまとめながら、疑問をなるべく残さないように調べながらゆっくり進めた2週目。
理解度もかなり上がったと思うし、記録してあるので調べやすいw
今後は自分なりに何かを作ったりしていきたいと思います。
web(セルフ)サービス!

らくだ🐫にもできるRailsチュートリアルとは

「ド」が付く素人のらくだ🐫が勉強するRailsチュートリアルの学習記録です。
自分用に記録していますが、お役に立つことがあれば幸いです。

調べたとはいえらくだ🐫なりの解釈や説明が含まれます。間違っている部分もあるかと思います。そんな所は教えて頂けますと幸いなのですが、このブログにはコメント機能がありません💧お手数おかけしますがTwitterなどでご連絡いただければ幸いです