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

※毎回書いたほうがいい気がするので書いておきます※
平文の部分をちょこちょこI18nで日本語化しているのですが
その部分に関しては特に記述していなくてもたまにコードが違ったりしています。
t(‘.hogehoge’)って部分です
どうぞお気になさらず。

13.3 マイクロポストを操作する

モデリングとテンプレートが完成したのでweb経由でマイクロポストを操作できるようにしていく

従来のRailsの開発の慣習と異なる部分

Micropostsリソースへのインターフェイスは、主にプロフィールページとHomeページのコントローラを経由して実行されるので、Micropostsコントローラにはnewやeditのようなアクションは不要ということになります。つまり、createとdestroyがあれば十分です。

よってMicropostのリソースは下記↓のように

提供されるRESTfulなルート → RoRT本文参照

13.3.1 マイクロポストのアクセス制御

Micropostsコントローラ内のアクセス制御から始める
→Micropostsは関連付けられたユーザーを通してアクセスされるので
createアクションやdestroyアクションを利用するユーザーはログインしている必要がある

ログイン済みかどうかを確かめるテストでは、Usersコントローラ用のテストがそのまま役に立ちます

ログイン済でない場合の動作↓

  1. 正しいリクエストを各アクションへ発行
  2. マイクロポストの数が変化していないか
  3. 正しくリダイレクトされているか

実装前のリファクタリング

ログインの有無を確認するためにbeforeフィルターで定義したlogged_in_userメソッド
→Usersコントローラで定義してあるけどMicropostsコントローラでも使いたい!
→各コントローラが継承するApplicationコントローラに移動する

重複しないようにUsersコントローラから該当部分を削除

Micropostsコントローラへbeforフィルターを追加

これでテストもGREEN!

演習

  1. なぜUsersコントローラ内にあるlogged_in_userフィルターを残したままにするとマズイのでしょうか? 考えてみてください。

1.
重複したコードはトラブルの元になる!
→片方だけ編集しちゃったりとか

重複したコードを残したまま片方を編集しちゃしまうとどうなるか

ApplicationControllerを継承したUsersControllerで重複したコードに一部変更があった場合
UsersControllerのコードが優先される→オーバーライド

オーバーライド(英:override)とは

オブジェクト指向におけるオブジェクトの継承の話で出てくる用語のひとつ

であり

親クラスにあるメソッドを子クラスで再定義することによって、子クラス上で親クラスのメソッドを上書きすること


今回は両方のコントローラーで同じ挙動をさせたいのにFインジェクション
重複コードを残したまま、それを忘れてどちらか一方を編集してしまうと呼び出すコントローラにより挙動が変わってしまう
→意図しない挙動になってしまうのでいくない!

13.3.2 マイクロポストを作成する

マイクロポストの作成用フォームはmicropost/newではなくルートパス(ホーム画面)に作る
参考画面は本文参考

最後にホーム画面を実装したときは (図 5.8)、[Sign up now!] ボタンが中央にありました。マイクロポスト作成フォームは、ログインしている特定のユーザーのコンテキストでのみ機能するので、この節の一つの目標は、ユーザーのログイン状態に応じて、ホーム画面の表示を変更することです。

Micropostのcreateアクション

基本的にはUsersコントローラのcreateアクションと似ているけど
User/Micropost関連付けを使って新しいマイクロポストを作る点が違っている
また、外部メソッドのmicropost_paramsでStrong Parametersを使い、マイクロポストのcontent属性だけをWeb経由で変更可能にしてある
実際のコード↓

マイクロポスト作成フォーム

専用ページではなくstatic_pages/home.html.erbにフォームを作る
更に、userがログインしているかどうかで表示を変える(ログインしていなければ今まで通り、していたらフォームを表示)
ひとまずこう↓

イマイチなので演習でリファクタリングするのだそうです

また、パーシャルもいくつか追加

マイクロポストの投稿フォームを動かす

homeアクションにマイクロポストのインスタンス変数を追加

これによりユーザーがログインしている時のみ@micropost変数が定義される

エラーメッセージのパーシャルを定義

_micropost_form.html.erb内のこのコード↓が動くようにするため

現在のエラーパーシャルはこう

このままではviewのこの↓コードが動かない

元々のエラーメッセージパーシャルでは@users変数を直接参照している
→今回は@micropost変数を参照したい!
→@users変数でも@micropostでも参照できたい!
→フォーム変数fをf.objectにして関連付けられたオブジェクトにアクセスできるようにする!

パーシャルにオブジェクトを渡すために、値がオブジェクトで、キーがパーシャルでの変数名と同じハッシュを利用します。これで、リスト 13.39の2行目のコードが完成します。言い換えると、object: f.objectはerror_messagesパーシャルの中でobjectという変数名を作成してくれるので、この変数を使ってエラーメッセージを更新すればよいということです

error_messagesパーシャルを更新してもテストはRED
→error_messagesパーシャルは他のviewからも呼び出されているため
関連するviewを更新するとGREENになる!
※users/new.html.erbとusers/edit.html.erbのフォームはパーシャルでまとめているので
 本文と違ってusers/_form.html.erbを更新する

GREENにならないね?って思ったら日本語化のアレでナニてったので直してGREEN!

演習

  1. Homeページをリファクタリングして、if-else文の分岐のそれぞれに対してパーシャルを作ってみましょう。

1.
それぞれのファイルを作って該当部分を移動
(I18n対応はja.yml作り直すの面倒だったので階層で指定)

それぞれを呼び出すコードを追加

13.3.3 フィードの原型

homeのページにマイクロポストが表示されるようにする→マイクロポストのフィードに実装
RoRT本文参照
全てのユーザーがフィードを持つので、feedメソッドはUserモデルに作る
→まずはログインユーザーのマイクロポストをすべて取得
→後々フォローしているユーザーのマイクロポストを含めたfeedを実装するので今回はwhereメソッドを使う

上記ハイライト行はセキュリティ上重要な役割を果たしている!

SQLクエリに代入する前にidがエスケープされるため、SQLインジェクション (SQL Injection) と呼ばれる深刻なセキュリティホールを避けることができます。この場合のid属性は単なる整数 (すなわちself.idはユーザーのid) であるため危険はありませんが、SQL文に変数を代入する場合は常にエスケープする習慣をぜひ身につけてください。

SQLインジェクションとは何ぞ

穴埋めになっているSQL文の穴埋め部分に、作った人が意図しない内容を入れることによって、おかしな動きをさせること。もしくは、それができるようになっている状態

Micropost.where(“user_id = ?”, id)とはなんぞ

プレースホルダー(? の事)を使った書き方
第一引数の user_id = ? の?に 第2引数の id が置き換わる


SQLインジェクションを避けることが出来る!
また、上記のコードは現状コレ↓と同等だけど後々(14章)の為にこの↑形に

フィード機能を実装していく

ログインユーザーのフィード用にインスタンス変数@feed_itemsを追加

これはRubyの慣習で、1行の時は後置if文、2行以上の時は前置if文を使う為

Homeページにフィード用のパーシャルを追加

この時

@feed_itemsにはcurrent_userに紐付いたfeedのpaginate(page: params[:page])が代入されており

feedってなんだっけって言うと

つまり@feed_itemsの各要素はMicropostクラスを持っている
よってRailsはMicropostのパーシャル(_micropost.html.erb)を呼び出すことができる。

このように、Railsは対応する名前のパーシャルを、渡されたリソースのディレクトリ内から探しにいくことができます。

→Homeページにステータスフィードを追加

※本文はapp/views/static_pages/home.html.erbになってるけど
13.3.2の演習でパーシャルに分けているので
「ログイン済の際に表示されるほう」のパーシャルにコードを追加する

現状の問題

現時点では、新しいマイクロポストの作成は図 13.15で示したように期待どおりに動作しています。ただしささいなことではありますが、マイクロポストの投稿が失敗すると、 Homeページは@feed_itemsインスタンス変数を期待しているため、現状では壊れてしまいます。

→「NoMethodError in Microposts#create」になる
回避用のコードを追加する

この状態でマイクロポストの投稿を失敗させるとfeedの表示がおかしくなる→[]を代入したため@feed_itemsがemptyの状態
(上記の件どこでなおすとか書いてないけど、14章で完成させる機能っぽいから14章でかなぁ🐫)

演習

  1. 新しく実装したマイクロポストの投稿フォームを使って、実際にマイクロポストを投稿してみましょう。Railsサーバーのログ内にあるINSERT文では、どういった内容をデータベースに送っているでしょうか? 確認してみてください。
  2. コンソールを開き、user変数にデータベース上の最初のユーザーを代入してみましょう。その後、Micropost.where(“user_id = ?”, user.id)とuser.microposts、そしてuser.feedをそれぞれ実行してみて、実行結果がすべて同じであることを確認してみてください。ヒント: ==で比較すると結果が同じかどうか簡単に判別できます。

1.

macropostsテーブルの指定のカラムに対応した値を配列の形で送信している

2.
動作確認のみにて省略

13.3.4 マイクロポストを削除する

マイクロポストを削除する機能を実装する!!!
→ユーザー削除と同様に「delete(削除)」リンクによって作動させる
ユーザーの削除は管理者ユーザーのみが実行できるという制限だったけど
マイクロポストの削除は投稿した本人のみが削除できるようにする

viewにリンクの追加とdestroyアクションの実装

Micropostsコントローラにdestroyアクションを定義していく

関連付けを使ってマイクロポストを見つけるようにしている点です。これにより、あるユーザーが他のユーザーのマイクロポストを削除しようとすると、自動的に失敗するようになります。

→correct_userフィルターを定義し、その中で削除したいマイクロポストがログインしているユーザーのものかを確認する

request.referrerメソッドとは何ぞ

このメソッドはフレンドリーフォワーディングのrequest.url変数 (10.2.3) と似ていて、一つ前のURLを返します (今回の場合、Homeページになります)13 。このため、マイクロポストがHomeページから削除された場合でもプロフィールページから削除された場合でも、request.referrerを使うことでDELETEリクエストが発行されたページに戻すことができるので、非常に便利です。

また、元に戻すURLが見つからなかった場合は、||演算子を使ってroot_urlにリダイレクトされるようになっている

演習

  1. マイクロポストを作成し、その後、作成したマイクロポストを削除してみましょう。次に、Railsサーバーのログを見てみて、DELETE文の内容を確認してみてください。
  2. redirect_to request.referrer || root_urlの行をredirect_back(fallback_location: root_url)と置き換えてもうまく動くことを、ブラウザを使って確認してみましょう (このメソッドはRails 5から新たに導入されました)。

1.
idがエスケープされている

2.
→動く

redirect_backメソッドで直前に実行したアクションへリダイレクト
引数のfallback_locationオプションで例外エラーが発生した際のリダイレクト先にroot_urlを指定している

13.3.5 フィード画面のマイクロポストをテストする

Micropostsコントローラの認可をチェックするテストと
まとめの統合テストを書いていく

テストの準備

マイクロポスト用のFixtureにそれそれ別のユーザーに紐付けられたマイクロポストを追加する
(今回は1つしか使わないけど後で他のマイクロポストも利用するとの事)

Micropostsコントローラの認可をチェックするテスト

自分以外のユーザーのマイクロポストを削除しようとすると適切にリダイレクトされるテスト

次に統合テスト

  1. ログイン
  2. マイクロポストのページネーションの確認
  3. 無効なマイクロポストを投稿
  4. マイクロポストの削除
  5. 他のユーザーのマイクロポストには [delete] リンクが表示されない

といった手順で書いていく
→テストを生成

テストを実装

機能は実装済なのでテストはGREEN!

演習

  1. リスト 13.55で示した4つのコメント (「無効な送信」など) のそれぞれに対して、テストが正しく動いているか確認してみましょう。具体的には、対応するアプリケーション側のコードをコメントアウトし、テストが redになることを確認し、元に戻すと greenになることを確認してみましょう。
  2. サイドバーにあるマイクロポストの合計投稿数をテストしてみましょう。このとき、単数形 (micropost) と複数形 (microposts) が正しく表示されているかどうかもテストしてください。ヒント: リスト 13.57を参考にしてみてください。
  1. 動作確認のみにて省略
  2. I18nで言語をjaにしている影響で単数形と複数形は関係ない感じになっちゃってるけどこう↓

まとめとか感想

長かったねええええええ!
本文に書いたけど、フィードの挙動がちゃんとしてないけど追々するのかな?
どこでするかわかったら追記するようにしたいと思います(曖昧

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

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

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