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

14.2 [Follow] のWebインターフェイス

フォロー/フォロー解除の基本的なインターフェイスを実装し
フォローしているユーザーとフォロワーにそれぞれ表示用のページを作成する!

14.2.1 フォローのサンプルデータ

rails db:seedを使ってDBにサンプルデータを登録する
先にサンプルデータを自動作成できるようにしておくことにより
WEBページの見た目から先に取り掛かることが出来、バックエンド機能の実装を後に回すことが出来る

  • userが3番目~51番目のユーザーをフォロー
  • 4番目~41番目のユーザーがuserをフォロー

準備完了!

演習

  1. コンソールを開き、User.first.followers.countの結果がリスト 14.14で期待している結果と合致していることを確認してみましょう。
  2. 先ほどの演習と同様に、User.first.following.countの結果も合致していることを確認してみましょう。

1も2も期待した通りの結果になっている
seedで作ったデータは(userに代入した)User.firstがフォローするほう(following)が先で
フォローされるほう(followers)が後だから
演習結果のカウントを見ると一瞬🤔ってなるね(コードを見ろと言われたらその通りなんだけど)

14.2.2 統計と [Follow] フォーム

サンプルユーザーにフォロイーとフォロワーが出来たので
プロフィールページとHomeページを更新してこれらが反映されるようにしていく!

  1. フォロイーとフォロワーの統計情報を表示するパーシャルを作る
  2. フォロー用とフォロー解除用のフォームを作る
  3. フォロイーとフォロワーそれぞれの一覧ページを作る

Twitterの慣習に倣ってフォロー数の単位には「following」を使うって事で参考画像も出てるけど
日本語ページだと「フォロー」「フォロワー」で出てるのでそうしようと思います

統計情報には、現在のユーザーがフォローしている人数と、現在のフォロワーの人数が表示されています。それぞれの表示はリンクになっており、専用の表示ページに移動できます。第5章では、これらのリンクはダミーテキスト’#’を使って無効にしていました。しかしルーティングについての知識もだいぶ増えてきたので、今回は実装することにしましょう

実際のページは次のセクションで作成するんだけどルーティングは先に実装しちゃうとの事

これにより/users/1/followingや/users/1/followersといったURL
following_user_path(1)やfollowers_user_path(1)といった名前付きルートが使えるようになる
RoRT本文参照

ルーティングのネスト


ルーティングをネストすることで紐付いているモデルの親子関係を表すことが出来るようになる

統計情報を表示するパーシャルを作成&表示

ハイライト行、
CSS idを指定しているのは、14.2.5でAjaxを実装するときに便利な為のと事

出来上がったパーシャルが表示されるようにrenderで呼び出すんだけど
本文はhome.html.erbに追加してるけど
どこかでhome.html.erbの内容もログインしてるかしてないかのif文でパーシャルを呼び出すようにしているので
ログインしている際に呼び出される_user_logged_in.html.erbに該当コードを追加する

スタイルも追加(14章で使うすべてのスタイルを追加しているので、まだ出てきてない属性もあるけどキニシナイ!!)

フォロー/フォロー解除フォームのパーシャル

↑これはfollowとunfollowのパーシャルに表示を分けているだけ
自分(ログインユーザー=current_user)に対してはフォロー・フォロー解除は存在しないので
unless current_user?(@user)の時のみブロック内を表示する
また、それぞれのパーシャルではRelationshipsリソース用の新しいルーティングが必要な為
routes.rbにコードを追加

ユーザーをフォローするフォームとフォロー解除するフォームでは
どちらもform_forを使ってRelationshipモデルオブジェクトを操作する
ユーザーをフォローするフォームでは新しいリレーションシップを作成するため
POSTリクエストをRelationshipsコントローラに送信してcreate (作成) する

ユーザーのフォローを解除するフォームでは既存のリレーションシップを見つけ出し
DELETEリクエストを送信してリレーションシップをdestroy (削除) する

最終的に、このフォロー/フォロー解除フォームにはボタンしかないことを理解していただけたと思います。しかし、それでもこのフォームはfollowed_idをコントローラに送信する必要があります。これを行うために、リスト 14.21のhidden_field_tagメソッドを使います。

hidden_field_tagメソッドが次のようなフォーム用のHTMLを生成してくれる

パスワードの再設定フォームの時のように
隠しフィールドのinputタグを使うことで、ブラウザ上に表示させずに適切な情報を含めることが出来る!

これらをまとめたプロフィール画面がこれ↓

ユーザー一覧ページから
未フォローのユーザーを表示させるとフォローボタンが
フォロー済のユーザーを選ぶとフォロー解除ボタンが表示される!

フォローボタンを動作させる為の2通りの方法

フォローボタンを使えるようにするためには
標準的(今までやってきた通り)な方法としてRelationshipsコントローラを作って制御する方法(14.2.4でやる)と
Ajaxという仕組みを使う方法(14.2.5でやる)がある
けど、その前に14.2.3でフォローしているユーザーとフォロワーを表示するページをそれぞれ作成してHTMLインターフェイスを完成させちゃうんだって!

演習

  1. ブラウザから /users/2 にアクセスし、フォローボタンが表示されていることを確認してみましょう。同様に、/users/5 では [Unfollow] ボタンが表示されているはずです。さて、/users/1 にアクセスすると、どのような結果が表示されるでしょうか?
  2. ブラウザからHomeページとプロフィールページを表示してみて、統計情報が正しく表示されているか確認してみましょう。
  3. Homeページに表示されている統計情報に対してテストを書いてみましょう。ヒント: リスト 13.28で示したテストに追加してみてください。同様にして、プロフィールページにもテストを追加してみましょう。
  1. /users/2も/users/5も書かれている通りに表示される
    /users/1は自分(current_user)なのでボタンは表示されない
  2. される
  3. リスト13.28で示されているのがプロフィールページのテストな気が🤔
    Homeページのテストだと/sample_app/test/integration/site_layout_test.rbと思うのでなんか作ったらいいのかな?

14.2.3 [Following] と [Followers] ページ

フォローしているユーザーを表示するページとフォロワーを表示するページは
プロフィールページとユーザー一覧ページを合わせたような作りになる
どちらもフォローの統計情報などのユーザー情報を表示するサイドバーとユーザーのリストがある
さらに小さいユーザープロフィール画像のリンクを格子状に並べて表示する
モックアップはRoRT本文参照
まずはフォローしているユーザーのリンクとフォロワーのリンクを動くようにする
Twitterに倣ってどちらのページでもユーザーログインを要求する形に

フォロー/フォロワーページの認可をテストする

今回のテストではfollowingとfollowersの名前付きルートを使っている

現状はまだRED
→Usersコントローラに2つの新しいアクションを追加する必要がある

これはリスト 14.15で定義した2つのルーティングにもとづいており、これらはそれぞれfollowingおよびfollowersと呼ぶ必要があります。それぞれのアクションでは、タイトルを設定し、ユーザーを検索し、@user.followingまたは@user.followersからデータを取り出し、ページネーションを行なって、ページを出力する必要があります。

Railsはアクションに対応するビューを暗黙的に呼び出してくれる
→例)showアクションの最後でshow.html.erbを呼び出す
上記のfollowing・followers両アクションはrenderを明示的に呼び出し、show_followという同じビューを出力している
よって、それぞれのアクションに別々のビューを用意するのではなくshow_followというビューを1つ作ればOK

実行されたアクションによってフォローしているユーザー・フォロワーのいづれかの一覧が表示される
また「現在のユーザー」を使っていない為、他のユーザーの一覧ページも正しく表示される

show_followの統合テスト

ここまでのテストはGREEN
ここからshow_followの描写結果の統合テストを書いていく
HTML構造を網羅的にチェックするテストは少しの変更でもREDになり、逆に生産性を落としかねない
→正しい数が表示されているかどうかと、正しいURLが表示されているかどうかの2つの基本的なテストに留める

統合テストを用意したらテスト用のデータをそろえる
→リレーションシップ用のfixtureにデータを追加

fixtureでは、前半の2つでMichaelがLanaとMaloryをフォローし、後半の2つでLanaとArcherがMichaelをフォローしています。

準備が出来たのでテストを書く

演習

  1. ブラウザから /users/1/followers と /users/1/following を開き、それぞれが適切に表示されていることを確認してみましょう。サイドバーにある画像は、リンクとしてうまく機能しているでしょうか?
  2. リスト 14.29のassert_selectに関連するコードをコメントアウトしてみて、テストが正しく red に変わることを確認してみましょう。

動作確認のみにて省略

[Follow] ボタン (基本編)

ビューが整ったので[Follow] / [Unfollow] ([フォローする]/[フォロー解除])ボタンを動作させる
フォローとフォロー解除はそれぞれリレーションシップの作成と削除に対応しているので、まずはRelationshipsコントローラを作成!

リレーションシップの基本的なアクセス制御とそれに対するテスト

まずはテストから!と言うことで
Relationshipsコントローラのアクションにアクセスする時、ログイン済のユーザーであるかどうかをチェックするテストを書く
ログイン済でなかった場合ログインページにリダイレクトされる→Relationshipのカウントが変わっていないことを確認

このテストをパスするためにRelationshipsコントローラのアクションに対してlogged_in_userフィルターを追加

Relationshipsコントローラのそれぞれのアクション

[Follow] / [Unfollow] ボタンを動作させるためには、フォーム (リスト 14.21リスト 14.22) から送信されたパラメータを使って、followed_idに対応するユーザーを見つけてくる必要があります。

その後、見つけてきたユーザーに対して適切にfollow/unfollowメソッドを実行する

もしログインしていないユーザーが (curlなどのコマンドラインツールなどを使って) これらのアクションに直接アクセスするようなことがあれば、current_userはnilになり、どちらのメソッドでも2行目で例外が発生します。エラーにはなりますが、アプリケーションやデータに影響は生じません。このままでも支障はありませんが、やはりこのような例外には頼らない方がよいので、上ではひと手間かけてセキュリティのためのレイヤーを追加しました。

logged_in_userフィルターはなくても支障はないけど、ちゃんと設定しておこうというお話

演習

  1. ブラウザ上から /users/2 を開き、[Follow] と [Unfollow] を実行してみましょう。うまく機能しているでしょうか?
  2. 先ほどの演習を終えたら、Railsサーバーのログを見てみましょう。フォロー/フォロー解除が実行されると、それぞれどのテンプレートが描画されているでしょうか?
  1. 動作確認のみにて省略
  2. どちらもusers/show.html.erb

14.2.5 [Follow] ボタン (Ajax編)

ユーザーはプロフィールページを最初に表示し、それからユーザーをフォローし、その後すぐ元のページにリダイレクトされるという流れになります。ユーザーをフォローした後、本当にそのページから離れて元のページに戻らないといけないのでしょうか

Ajaxを使ってWebページからサーバーに「非同期」で、ページを移動することなくリクエストを送信する


Railsでも簡単にAjaxを実装することが出来る

Ajaxを使ったフォーム

実際に定義するとこうなる

生成されるTHMLに関しての解説などはRoRT本文参照

Ajaxリクエストに対応するRelationshipsコントローラ

こういったリクエストの種類によって応答を場合分けするときは、respond_toメソッドというメソッドを使います。

RelationshipsコントローラでAjaxに対応させるためにrespond_toメソッドをそれぞれのアクションに追加する

このとき、ユーザーのローカル変数 (user) をインスタンス変数 (@user) に変更した点に注目してください。

初めはインスタンス変数は必要なかったけど、Ajaxを使ったフォームを実装したことによりビューでインスタンス変数が必要になったため

また、今度はブラウザ側でJavaScriptが無効になっていた場合でもうまく動くようにする
(JavaScriptが無効→Ajaxリクエストが送れない)

難しいことはよくわからなかったんだけど
JSを有効にする設定という事?


ユーザーをフォローしたときやフォロー解除したときにプロフィールページを更新するために
JavaScript用の埋め込みRuby (.js.erb) ファイル (create.js.erbやdestroy.js.erbなど) を編集していく

純粋なJavaScriptと異なり、JS-ERbファイルでは組み込みRuby (ERb) が使えます。create.js.erbファイルでは、フォロー用のフォームをunfollowパーシャルで更新し、フォロワーのカウントを更新するのにERbを使っています (もちろんこれは、フォローに成功した場合の動作です)。

フォロー解除した場合はfollowパーシャルで更新

escape_javascriptメソッドとは何ぞ

JavaScriptファイル内にHTMLを挿入するときに実行結果をエスケープする

エスケープしておかないと文字化けでうまく作動しなくなる

演習

  1. ブラウザから /users/2 にアクセスし、うまく動いているかどうか確認してみましょう。
  2. 先ほどの演習で確認が終わったら、Railsサーバーのログを閲覧し、フォロー/フォロー解除を実行した直後のテンプレートがどうなっているか確認してみましょう。
  1. 動作確認のみにて省略
  2. フォロー→ relationships/create.js.erb
    フォロー解除→ relationships/destroy.js.erb

14.2.6 フォローをテストする

フォローボタンを設置できたので、バグを検知するためにシンプルなテストを書いていく!

ユーザーのフォローに対するテストでは、 /relationshipsに対してPOSTリクエストを送り、フォローされたユーザーが1人増えたことをチェックします。

通常の、コントローラからアクションを呼び出す形式のフォロー/フォロー解除のテストに加え
Ajaxを利用した場合のテストも必要になる!→「xhr :true」オプションを追加するだけ!

演習

  1. リスト 14.36のrespond_toブロック内の各行を順にコメントアウトしていき、テストが正しくエラーを検知できるかどうか確認してみましょう。実際、どのテストケースが落ちたでしょうか?
  2. リスト 14.40のxhr: trueがある行のうち、片方のみを削除するとどういった結果になるでしょうか? このとき発生する問題の原因と、なぜ先ほどの演習で確認したテストがこの問題を検知できたのか考えてみてください。

1.

それぞれのformat.js行のみをコメントアウトした場合はテストは落ちない
実際の処理が何で行われているかではなくてブロック内の処理の前後で@user.following.countが変化しているかをテストしているからってことだと思う
with Ajaxじゃないのって思うけど「そういうもの」と思っていてよいっぽい
2.

@user.following.countが変わらないのでエラーになる
なぜか→ブロック内で何の処理も行っていない為

まとめとか感想

難しかったって言うか
14.2.6の演習が、そもそも日本語の文章の意図がわからなくてわからん🤔となりましたね。
結局難しくて追いきれなかったんだけど
「そういうもの」って事でいいのかな?って不安だったところを
「そういうものって事でいいかと」って言ってもらったので心置きなくそういう事にしました!

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

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

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