Railsチュートリアルで学んだことメモ

Railsチュートリアル

1章 ゼロからデプロイまで

やったこと

  • Railsアプリの作成
  • Git管理
  • Renderデプロイ

2章 Toyアプリケーション

やったこと

  • scaffoldでToyアプリの作成
  • Userモデル設計
  • MicroPostモデル設計(ツイートのようなもの)
  • usersリソースをscaffoldで作成
  • REST
  • micropostsリソースをscaffoldで作成
  • userとmicropostsを関連づける
  • クラスを継承することで多くの機能をデフォルトで使える
  • Toyアプリのデプロイ

学んだこと

  • scaffoldだけではバリデーションやテスト、レイアウトは作れない

3章 静的なページの作成

やったこと

  • sample_appのセットアップ、デプロイ
  • static_pagesコントローラを作成
  • rails gとrails d
  • rails db:migrateとdb:rollback
  • HTTPメソッド
  • erb
  • テスト
  • static_pagesコントローラのテスト
  • テスト駆動開発
  • titleを動的にする
  • レイアウトファイル
  • rootのルーティングを指定
  • minitestの出力のフォーマット
  • Guardによるテストの自動化

学んだこと

  • コントローラはApplicationControllerを継承しているので、メソッドに何も書かなくても特有の処理を行う
  • テストを先に書くか後に書くかの目安
    • アプリケーションのコードよりも明らかにテストコードの方が短くシンプルになる(=簡単に書ける)のであれば、「先に」書く
    • 動作の仕様がまだ固まりきっていない場合、アプリケーションのコードを先に書き、期待する動作を「後で」書く
    • セキュリティが重要な課題またはセキュリティ周りのエラーが発生した場合、テストを「先に」書く
    • バグを見つけたら、そのバグを再現するテストを「先に」書き、回帰バグを防ぐ体制を整えてから修正に取りかかる
    • すぐにまた変更しそうなコード(HTML構造の細部など)に対するテストは「後で」書く
    • リファクタリングするときは「先に」テストを書く。特に、エラーを起こしそうなコードや止まってしまいそうなコードを集中的にテストする
  • content_forの代替がprovide

4章 Rails風味のRuby

やったこと

  • 組み込みヘルパー
  • カスタムヘルパー(自作メソッド)
  • title属性を動的に変更
  • Railsコンソール
  • 文字列
  • オブジェクトとメッセージ(メソッド)受け渡し
  • 配列
  • 範囲演算子(range)
  • ブロック
  • ハッシュ
  • シンボル
  • stylesheet_link_tag
  • クラス

学んだこと

  • シングルクォートとダブルクォートは違いはほぼないのでどっちでもいい
  • nilもオブジェクト
  • nilとfalseだけが論理値がfalseになる
  • 配列の内容を変更したい場合はメソッドに!をつける
  • Rubyでは異なるデータ型が配列の中で共存できる
  • ブロックはメソッドの引数に渡す処理のようなもの
  • inspectメソッドはオブジェクトを文字列で表現する = pメソッド
  • ハッシュがメソッド呼び出しの最後の引数である場合は、波カッコを省略できる
  • RubyではすべてのオブジェクトはBasicObjectを継承しているので、あらゆるものがオブジェクトである
  • RubyのドキュメントではクラスメソッドはString.newのように.で表記して、インスタンスメソッドはString#lengthのように表記する
  • RailsRubyは別物なのでコントローラなどはnewを実行しなくても使える
  • アクションには戻り値がない
  • インスタンス変数はそのクラス内のどこからでもアクセスできる、ビューで使える
  • インスタンス化するときに引数にハッシュを渡すことをマスアサインメントという
  • 文字列の比較は1文字ずつだが、シンボルは一度に全体を比較できる

5章 レイアウトを作成

やったこと

  • レイアウトを作成する
  • 静的ページを作成
  • Bootstrapを使う
  • link_to
  • image_tag
  • パーシャルで整える
  • ルーティング
  • アセットパイプライン
  • Sass
  • ユーザー登録
  • 統合テスト

学んだこと

  • image_tagは画像ファイルのパスと任意のオプションハッシュを受け取る
  • image_tagを使うとRailsは該当する画像ファイルをアセットパイプラインを通してapp/assets/imagesから探す
  • image_tagのsrc属性にはimagesというディレクトリがなく、assetsディレクトリ直下の画像をapp/assets/imagesと紐づけている
  • アセットパイプラインを理解するにはアセットディレクトリ、マニフェストファイル、プリプロセッサエンジンを理解する
  • マニフェストファイルは静的ファイルをどのように1つにまとめるかを指示するファイル(画像ファイルは適用されない)
  • アセットをまとめる処理を行うのSprockets
  • *= require_tree .はapp/assets/stylesheetsの中のすべてのCSSファイルを含める
  • *= require_selfは自身のファイルも対象に含める
  • アセットパイプラインのメリットは開発環境ではプログラマにとって読みやすいフォーマットで、本番環境では最適化されたアセットを自動的に生成できること
  • 多くのRails開発者は、異なるビューの間で共通して使うパーシャル用のディレクトリとして、sharedディレクトリをよく使う、全ページ共通のパーシャルはlayoutsディレクトリに保存する

6章 ユーザーのモデルを作成する

やったこと

  • Userモデルを作成
  • マイグレーション
  • バリデーション
  • インデックス
  • コールバック
  • セキュアなパスワードを追加

学んだこと

  • マイグレーションのchangeメソッドはdrop_tableとcreate_tableが対応していることを知っているためロールバックが可能になる
  • モデルクラスはApplicationRecordを継承するので、自動的にActiveRecord::Baseクラスのすべての機能を持つ
  • newメソッドはメモリ上でオブジェクトを作成しただけ
  • createメソッドは真偽値ではなく、オブジェクト自身を返す
  • validatesは単なるメソッド
  • 通常メールアドレスは大文字と小文字が区別されない
  • インデックスを追加するときはそのカラムで検索が頻繁に発生するか考える
  • セキュアなパスワードでは、パスワードと確認用のパスワードを入力させ、ハッシュ化してDBに保存する
  • ハッシュ化とは、入力されたデータを復元不可能なデータに変換する処理
  • ユーザーの認証はパスワードの送信→ハッシュ化→DB内のハッシュ化された値との比較で手順が進む
  • セキュアなパスワードはUserモデルで、has_secure_passwordを呼び出すだけでほぼ完了する
    • has_secure_passwordでDB内でpassword_digest属性を保存できる
  • has_secure_passwordを使うにはbcryptライブラリが必要
  • !!を使うことでオブジェクトが対応する論理値に変換できる
  • authenticateは成功するとユーザーオブジェクトを返すが、!!をつけることで、trueを返す
  • 暗号化は元に戻せて、ハッシュ化は元に戻せない

7章 ユーザー登録

やったこと

  • ユーザーページを表示する
  • デバッグ
  • Gravatarを使ったプロフィール写真の導入
  • ユーザー登録フォーム
  • form_with
  • ユーザー登録失敗
  • ストロングパラメータ
  • エラーメッセージのパーシャル化
  • ユーザー登録成功
  • リダイレクト
  • フラッシュメッセージ
  • プロ品質のデプロイ

学んだこと

  • findメソッドでは自動的に整数型に変換される
  • form_withはActive Recordのオブジェクトを取り込み、その属性を使ってフォームを構築する
  • form_withではモデルオブジェクトが必要
  • ストロングパラメータでは必須と許可済みのパラメータを指定できる
  • Raildではデフォルトでparamsハッシュを丸ごと渡すとエラーが発生する
  • privateのメソッドのインデントは一段深くする
  • TLSはローカルのサーバーからネットワークにデータを送信する前に大事な情報を暗号化する技術
  • production.rbでconfig.force_sslをtrueにすることでTLSを強制する
  • 本番サイトでTLSを使うためには自分のドメインで使用するTLS/SSL証明書が必要
  • RailsではデフォルトでPumaが使える
  • リンクのパスとしてモデルオブジェクトが渡されると自動的にidになる

8章 基本的なログイン機構

やったこと

  • セッション
  • ログイン
  • ログインフォーム
  • メールアドレスからユーザーを取得し、パスワードで認証する
  • フラッシュメッセージでエラーを表示
  • フラッシュのテスト
  • セッションヘルパー
  • セッションハイジャック
  • セッション固定
  • メモ化
  • 短絡評価
  • ログイン状態によってレイアウトリンクを変更する
  • JavaScriptを導入する
  • ドロップダウンメニュー
  • モバイル向けスタイリング
  • ログイン状態のレイアウトの変更のテスト
  • fixtureでテストデータを定義
  • ユーザー登録後にログインする
  • テスト用のログイン状態のメソッドを作成
  • ログアウト
  • テストのリファクタリング

学んだこと

  • Cookieとはユーザーのブラウザに保存される小さなテキストデータ
  • セッションはブラウザを閉じると自動的に終了する
  • Cookieにセッションを保存する
  • セッションはActive Recordオブジェクトではないので、デフォルトのエラーメッセージはつかない、またform_withでもurlやスコープを指定する必要がある
  • form_withでscopeを指定することで、name属性の値を決める
  • flashではなくflash.nowだとリクエストが発生すると消滅する
  • セッションはRailsの事前に定義されているsessionメソッドをハッシュのように使う
  • sessionメソッドを使うとユーザーのブラウザ内の一時cookieに暗号化された値が保存される
  • セッションハイジャックやセッション固定に備える必要がある
  • セッション固定に対策するにはログイン前にreset_sessionを使う
  • ||=を使ってメソッドの結果を変数に保持して次回以降の呼び出しを再利用する方法をメモ化という
  • current_userを渡すことでUserのページに遷移できる
  • ぼっち演算子を使うと、object && object.methodobject&.methodに短縮できる
  • ログアウトはセッションを削除するよりすべてのセッション変数をリセットして行う
  • RailsでTurboを使うときはDELETEリクエスト後のリダイレクトが正しく動作するようにstatus: :see_otherを指定する必要がある
  • ヘルパーはコントローラ用で、モデルはconcern
  • ブラウザによっては、「中断したところから続ける」機能でセッションを復元するオプションを提供しているものもあるが、Railsはこの動作を制御できない

9章 発展的なログイン機構

やったこと

学んだこと

  • Remember meを実装するには記憶トークンを生成し、トークン認証を行う
  • トークンとはパスワードの平文と同じような秘密情報で、パスワードはユーザーが、トークンはコンピュータが作成・管理する
  • Railsでは自動的にビューテンプレートで入力した内容をすべてエスケープする
  • 永続的セッションの作り方
    1. ランダムな文字列を記憶トークンとして使う
    2. 記憶トークンをハッシュ化してDBに保存する
    3. 記憶トークンをブラウザのCookieに保存するときは有効期限を設定し、ユーザーIDを暗号化する
    4. もしブラウザのCookieに暗号化されたユーザーIDがあれば、復号したユーザーIDでデータベースを検索し、データベース内のハッシュ値と一致するか確認する

10章 ユーザーの更新・表示・削除

やったこと

  • ユーザーのプロフィールを更新する
  • 認可モデル
  • フレンドリーフォワーディング
    • ユーザーが直前に開こうとしていたページにリダイレクト先を指定すること
  • すべてのユーザーを一覧できる
  • seedでサンプルデータを作成
  • ページネーション
  • リストのパーシャル化
  • ユーザーの削除
  • 管理ユーザー
    • カラムを追加
  • 本番環境でのサンプルデータ生成

学んだこと

  • beforeフィルターでアクセス制御を実装する
  • リンクのtarget="_blank"にはセキュリティ上の小さな問題がある
  • ブラウザはPATCHリクエストをそのままでは送信できないので、input hiddenを使ってPOSTリクエストをPATCHリクエストとして偽造する
  • form_withはnew_record?によって新規作成(POST)か更新(PATCH)を判断する
  • アプリの実装前に統合テストを書くことを受け入れテストという
  • 名前やメールアドレスを変更するときにパスワードは入力せずに更新できると便利
  • バリデーションでallow_nil: trueにするとフィールドが空の時に有効にできる
  • 編集・更新処理はユーザー自身のページであるか確認する
  • request.original_urlでリクエスト先が取得できる
  • ブラウザはネイティブではDELETEリクエストを送信できないため、RailsではJavaScriptを使って「偽造」する
  • JavaScriptが使えないブラウザをサポートする必要がある場合は、フォームとPOSTリクエストを使ってDELETEリクエストを偽造することも可能
  • Railsではadmin属性をUserモデルに追加すると自動的にadmin?という論理オブジェクトを返すメソッドが追加される
  • adminのような編集可能にしてはならない属性はテストを作るべき

11章 アカウントの有効化

やったこと

  • メール送信
  • アカウント有効化の作成手順
    1. 有効化トークンやダイジェストを関連づける
    2. 有効化トークンを含めたリンクをユーザーにメールで送信する
    3. ユーザーがリンクをクリックすると有効化できるようにする
  • アカウント有効化の手順
    1. ユーザー登録が行われる
    2. サーバー側で有効化トークンが作られ、ハッシュ化され、ユーザーデータに登録される
    3. アカウント有効化のためのリンクを持つメールがユーザーに送信される
    4. ユーザーがメール内のリンクをクリックする
    5. ユーザーのメールアドレスと有効化トークンがサーバーに送信される
    6. トークンを比較し、一致すればアカウントをアカウントを有効化し登録が完了する
  • メールのプレビューの作成
  • メタプログラミング
  • 本番環境でのメール送信

学んだこと

  • 有効化トークンもハッシュ化する
  • ユーザー登録を完了するにはアカウントの有効化が必要になるので、有効化トークンはユーザーオブジェクトが作られる前に作る必要がある
  • クエリパラメータを設定するには名前付きルーティングに対してハッシュを追加する
  • クエリパラメータを名前付きルーティングで定義すれば、Railsが特殊な文字を自動的にエスケープしてくれる
  • Railsでは、特殊なURLにアクセスするとメールのメッセージをその場でプレビューできる
  • メタプログラミングはプログラムでプログラムを作成すること
  • メール送信で使うAction Mailerのメール送信のコントローラとビューを生成できる
  • Action MailerはテキストとHTMLの両方のメールを使える

12章 パスワードの再設定

やったこと

  • パスワードの再設定の手順
    1. ログイン画面でリンクをクリック
    2. 再設定画面に移動
    3. メールアドレスを送信
    4. パスワード再設定用のリンクを記載したメールを送信
    5. リンクをクリックする
    6. パスワード再設定ページに移動
  • パスワード再設定の処理の流れ
    1. 送信されたメールアドレスからユーザーを取得する
    2. ユーザーが存在する場合は、再設定用トークンを生成しハッシュ化する
    3. 再設定ダイジェストをDBに保存し、再設定用トークンをメールアドレスと一緒にユーザーに送信する有効通うメールのリンクに仕込む
    4. メールのリンクがクリックされたら、メールアドレスをキーとしてユーザーを探索し、DBの再設定ダイジェストと比較する(トークン認証)
    5. 認証に成功したら、パスワード変更用のフォームをユーザーに表示する
  • PasswordResetsのルーティングを生成
  • PasswordResetsのコントローラを生成
    • new
    • create
      • トークンを生成し、ハッシュ化
      • パスワード再設定のメール送信
      • フラッシュメッセージを表示
      • ルートにリダイレクト
    • edit
    • update
      • パスワード再設定の有効期限が切れていないか
      • 無効なパスワードでないか
      • パスワードが空ではないか
      • パスワードが正しければ更新するw
  • ログイン画面にパスワード再設定のリンクを追加
  • usersテーブルにreset_digestreset_sent_atを追加するマイグレーションを作成
  • パスワード再設定のメールテンプレートを作成
  • プレビューを作成
  • パスワード再設定のテスト
  • Mailgunで本番環境でのメール送信

学んだこと

  • パスワードの再設定はアカウント有効化とほぼ手順は同じ
  • 再設定用のリンクはなるべく短時間で期限切れにすべきなので、再設定メールの送信時刻も記録する

13章 ユーザーのマイクロポスト

やったこと

  • Micropostモデルの作成
  • バリデーション
  • Userとの関連付け
  • default_scope
  • マイクロポストを表示する
  • マイクロポストのアクセス制御
  • マイクロポストを作成
  • マイクロポストを削除
  • マイクロポストの画像投稿
  • Active Storageのインストール
  • JavaScriptで画像アップロードの警告を表示
  • ImageMagickで画像のリサイズ
  • AWS S3に画像を保存する

学んだこと

  • String型でもText型でもパフォーマンスの差はない
  • マイグレーションファイルのadd_indexで複数のカラムを配列に含めると、複合キーインデックスを作成する
  • default_scopeで使われる->はラムダというProcやlambda、無名関数と呼ばれるオブジェクトを作成する文法の省略記法で、ブロックを引数に取り、Procオブジェクトを返す
  • ラムダはcallメソッドが呼ばれた時にブロック内の処理を評価する
  • time_ago_in_wordsで何日前かを表すことができる
  • newではなくbuildを使うことで、関連付けしたオブジェクトを作成できる
  • SQLクエリに代入するときは?を使うことで、SQLインジェクションを回避できる
  • 1行のときは後置if文、2行以上のときは前置if文を使うのがRubyの慣習
  • 常に元のページに戻るにはrequest.referrerを使う
  • RailsでファイルをアップロードするにはActive Storageを使う
  • Active StorageはPDFや音声ファイルも扱える
  • has_one_attachedでモデルとアップロードされたファイルを関連づける
  • has_many_attachedでモデルと複数のアップロードされたファイルを関連づける
  • Active Storageにはバリデーションがないので、専用のgemを使う
  • 開発環境と本番環境では画像の保存先が異なる
  • JavaC++といった言語の挙動とは異なり、RubyのPrivateメソッドは継承クラスからも呼び出すことができる
  • エッジケースとは、滅多に起こらないがユーザーが遭遇する可能性があるバグのこと

14章 ユーザーをフォローする

やったこと

  • リレーションシップモデル
  • memberとcollection
  • フォロー
  • フォロー解除
  • ステータスフィード
  • Hotwire
  • N+1問題

学んだこと

  • フォロー機能では同じユーザーを2回フォローできないようにfollowed_idとfollower_idを使って複合インデックスキーを作ってユニークキーを指定する
  • << 演算子は、has_many や has_many :through アソシエーションを通じて関連付けられたオブジェクトを追加し、その変更をデータベースに保存できる
  • Hotwireを使うとページの一部分だけを変更できる
  • Turboは、Turbo Streamsと呼ばれる部分を介して動作し、小さなHTMLスニペットをWebSocketで直接ページに送信する
  • WebSocketは、クライアント(Webブラウザなど)とWebサーバーの間に持続的なコネクションを設定するWeb標準の技術
  • Turbo Streamに応答するものが存在しない場合は、RailsがデフォルトでTurbo Streamリクエストを通常のHTMLリクエストと同様に扱う
  • following_idsは、has_many :following関連付けを行うとActive Recordによって自動生成されるメソッド
  • SQLで同じ変数を複数の場所に挿入したい場合は、後者のハッシュ形式の構文の方がより便利