現場で使えるRuby on Rails5 速習実践ガイドを読んで

Railsを学ぶために「現場で使えるRuby on Rails5速習実践ガイド」を読んで、写経しました。

感想

今までWebやLinuxRubySQLなどを学んできて、ようやく実際のアプリを作っていく段階までこれました。 一通り本を読んで写経しましたが、Railsっていうかフレームワークってすげーって感じです。いろんな機能をちょこっとコードを書くだけで実装できました。


Railsの基本的な内容が主ですが、かなり実践的だと思います。Railsの話だけでなく、フロント側のJavaScriptや、テスト、チーム開発の進め方など、Railsに関わる全般的な内容を網羅しています。 かなり内容が濃く、写経にも時間がかかったので、何周もやるよりはさっさとアウトプットして理解を進める方が早いと思います。特に10章はリファクタリング的な内容でもあるので、アプリを作れるようになってからじゃないと身につかないと思います。


書籍ではrbenvを使って環境構築を行うのですが、Dockerを使って環境構築を行いました。ただしDockerだとブラウザテストやメール送信、非同期処理などが書籍通りの設定ではできないため、そこの設定に詰まりました。 あと本番環境のデータベースの作成でも詰まって解決しなかったので、一旦置いておいて実際にアプリを作った時にもう一度読み直そうと思います。

様々なgemを使うので、それぞれのドキュメントを見たり、よく使われるgemを把握しておこうと思います。

新しく学んだこと

細かい実装方法までは記述せず、インデックスを作る感じでまとめておきます。

2章 Railsアプリケーションをのぞいてみよう

  • rbenvでRubyのバージョンを切り替えることができる
  • rails generate scaffold userでユーザーに関するscaffoldを自動生成できる
  • MVCの処理の流れ

    1. URLにアクセスする
    2. コントローラが呼ばれ、リクエストに対するアクションメソッドが実行される
    3. データを扱うときはモデルを呼び出す
    4. 画面を表示するためにビューが呼び出される
  • オブジェクトとRDBを対応づけて便利に利用することができる機能をO/Rマッピング(Object-relational mapping)という

  • ビューで利用できる便利な機能のことをヘルパーメソッドという
  • ERBによってRubyのコードをHTMLに埋め込むことができる
  • <% %>Rubyのコードの実行だけ行う
  • <%= %>Rubyのコードの実行結果をHTMLに表示する

  • database.ymlはデータベースと接続するための設定ファイル

  • database.ymlにはdevelopment(開発)、test(テスト)、product(本番)の3つの環境のデータベースに接続する設定が記述されている

  • YAMLは構造化されたデータを表現するフォーマットで、データの保存や設定ファイルによく使われる

  • routes.rbはルーティングを定義するファイル

  • ルーティングはリクエストに対するレスポンスを作るためにどの処理を実行するかを定義したもの
  • rails routesコマンドで定義されたルーティングを確認できる

  • MVCとはソフトウェアの構造の考え方の1つ

    • モデルはデータとアプリ特有の処理であるビジネスロジックを実装するもの
    • ビューはブラウザに表示するHTMLなどを実装するもの
    • コントローラはリクエストを受け、適切なレスポンスを返すための制御を行うもの

3章 タスク管理アプリケーションを作ろう

  • 開発時の動作確認のためのデータと、実際に公開してユーザーが使うアプリのデータは性質が異なる

ビュー

  • テンプレートエンジンはHTMLの雛形と記述された動的な処理から最終的なHTMLを生成する仕組み
  • RailsのデフォルトのテンプレートエンジンはERB
  • Sassを使うことでCSSを効率よく記述できる
  • Railsはアプリ全体で1つのCSSファイルを読み込むようになっている
  • Railsのエラーメッセージはデフォルトで英語になっているので、必要なら他の言語に変換する
  • link_toはaタグを出力するメソッド
  • routes.rbの定義によって自動的に生成されたURLヘルパーメソッドによってURLの文字列を取得できる
  • form_withメソッドによってモデルと紐づいたform要素を出力できる
  • 共通して使いたい部分はパーシャルを使って共通化する
  • render partial:でパーシャルを指定する

モデル

  • モデルは全体的な設計や下準備の後に作るのが一般的
  • モデルは対応するRubyのクラスとデータベースのテーブルから構成される
  • モデルの属性とテーブルのカラムは対応する
  • ID、登録日時、更新日時はよく使われる属性なのでRailsが自動で用意する
  • モデルを作成するにはrails g model [モデル名] [属性名:データ型 ...]を実行する → モデルクラスのファイル、マイグレーションファイル、モデルの自動テストのファイル、テストで使うためのデータ投入の定義ファイルを作成する
  • データベースの操作はマイグレーションというデータベースへの変更をRubyのプログラムとして実行する仕組みを使う
  • マイグレーションは前の状態にも戻せる
  • saveでデータを保存する
  • allでデータを全件取得する
  • findで引数に渡された値に対応するデータを取得する
  • updateでデータを更新する
  • destroyでデータを削除する

コントローラ

  • rails g controller [コントローラ名] [アクション名]でコントローラファイルを生成できる
  • ルートのパスにアクセスしたときのルーティングはroot to:で指定する
  • アクションにインスタンス変数を作ることでビューに受け渡すことができる
  • paramsメソッドで送られてきたリクエストパラメータをHashで取得できる
  • 想定通りのリクエストパラメータかどうか判断し、受け付ける値だけを抜き取るための仕組みがStrong Parameters
  • ビューを表示させるのをrender
  • 別のURLに遷移するのがredirect_to
  • 次のリクエストに対して何かしらのメッセージを残すためのものがFlashメッセージ

4章 現実の複雑さに対応する

マイグレーション

  • 1つのマイグレーションファイルは1つのバージョンとして扱われる
  • マイグレーションはデータベースごとに適用される
  • マイグレーションファイルの名前はアプリ内で一意でなければならないので具体的な名前をつける
  • db/schema.rbで現在のデータベースの構造を見ることができる
  • upメソッドでバージョンを上げる、downメソッドでバージョンを下げる

データの内容を制限する

  • NOT NULL制約はnull: falseで指定する
  • 文字列の長さはlimit: [文字数]で指定する
  • UNIQUEインデックスの作成はunique: trueで指定する

バリデーション

  • モデルの検証とデータベース側の制限のどちらも行っておく
  • saveメソッドは自動的に検証を行い、エラーがあればfalseを返す
  • save!だとfalseではなく例外を発生させるので、検証エラーのハンドリングを行わない場合はこっちを使う
  • フォームの入力を保持したいときは、検証エラーが発生した時にリダイレクト先に入力された値を渡す
  • [model].errors.full_messagesでエラーメッセージを取得できる

コールバック

  • コールバックとは後で読んで欲しい処理をあらかじめ指定しておく仕組みであり、これによって登録や削除などのイベントの前後に任意の処理を実行できる

ログイン

  • Railsのデフォルトのセッションデータの保管場所はCookie
  • パスワードを使うときはモデルでhas_secure_passwordを使う(bcryptというgemが必要)
  • Railsでログイン機能を実装する時はSessionControllerという名前のコントローラがよく使われる
  • ログインしているユーザーはセッションのuser_idで取得する
  • ログアウトはセッションのuser_id、もしくはセッションのデータを破棄するだけ
  • ログインが必要な操作を実行できないようにするためにはコントローラでフィルタを使ってリダイレクトさせるようにする
  • データベースのテーブルの関連を実装するにはモデルでhas_manybelongs_toなどを記述する

データを絞り込む

  • データを絞り込んで検索等を行うときは、何からどんな条件で絞り込んでどう実行するかを意識する
  • クエリー用のメソッドは実行部分に当たるメソッドを呼ぶことで実行される

scope

  • scopeを使うことで、検索条件を定義して繰り返し使えるようにできる

5章 テストをはじめよう

テストのメリット

  • コードの新しい変更によってエラーが起きないか自動的にチェックできるので気軽に変更できる
  • バージョンアップやリファクタリングを行いやすい
  • テストによってメソッドがどんな振る舞いをするか読み取ることができる
  • テストをアプリの仕様として扱える
  • テストを書きやすいようにコードを書くと管理しやすいコードになる

RSpec

  • 動く仕様書として自動テストを書くという発想で作られたテスティングフレームワーク
  • 準備
    1. Gemfileのgroup :development, :test do end内にgem 'rspec-rails'を記述してインストール
    2. rails g repec:installで必要なディレクトリやファイルをインストール
    3. specディレクトリを使うため、Minitestで使うtestディレクトリを削除
  • Specの書き方
    • テストケースを整理・分類する
      • describe - 仕様を記述するテスト対象
      • context - テストを実行する際の条件
    • テストコードを実行する
      • it - テストケース
      • before - テストを実行する前の事前準備
    • その他
      • let - 変数のように扱え、上書きもできる
      • shared_examples - itを共通化してテストケース間でシェアできる
      • it_behaves_like - shared_examplesを実行する

重要なテストの種類

Specが失敗した時の調査方法

  • Specが失敗した時は失敗したSpecの場所と失敗した理由が結果として表示される
  • Failure/Errorの部分に失敗したテストコードの内容とエラーメッセージが表示される
  • コンソールで実際にコードが動くか確認する
  • スクリーンショットを確認する

6章 Railsの全体像を理解する

ルーティング

  • RailsはHTTPでクライアントとやりとりするサーバーサイドのプログラムを作るためのフレームワークなので、クライアント側のHTMLやJavaScriptの理解も重要
  • ルーティングはユーザーが触れるURLやHTTPメソッドと、開発者側のコントローラ・アクションの連携を担っている
  • RailsのルーティングはRESTfulなインターフェースを作りやすいようになっている
  • resourcesで7つのアクションに対する7つのルートを定義できる
  • ルートはControllerごとで管理するのが良い

国際化

  • Railsのアプリを様々な国に対応させることを国際化という
  • 国際化するためにやること
    • 翻訳データのymlファイルをconfig/localesに作成する
    • config.i18n.default_localeを設定する

日時

エラー処理

  • 環境ごとの設定ファイルのconfig.consider_all_requests_localがtrueの時にデバッグ用、falseで本番用のエラー画面が表示される
  • デフォルトでは404、422、500のエラー画面が用意されている

ログ

  • Railsのサーバーを起動しているとログが出力される
  • ログはlog/development.logにも出力される
  • 自分でログを出力させたい時はloggerオブジェクトを使う
  • デフォルトのログレベルがdebugなので、すべてのログレベルが出力される
  • ログに出力したくない値はconfig/initializers/filter_parameter_logging.rbRails.application.config.filter_parametersに設定する

セキュリティ

  • Railsには標準でセキュリティを高める機能が備わっているのである程度は意識する必要はない
  • リクエストを偽造してユーザーがログインしているアプリに悪意ある操作を行う攻撃がCSRF
  • Railsの場合、アクセスしているのがユーザー本人かはCookieを利用したセッションで判断する
  • CSRFは同じアプリからのリクエストであることを証明するセキュリティトークンを発行して照合することで対策する
  • Railsの提供しているform_withなどを使うとセキュリティトークンの仕組みが自動的に作られる
  • インジェクションはアプリに悪意のあるスクリプトや値が入力される攻撃
  • XSSの対策は危険なHTMLタグをそのまま解釈しないようにエスケープする
  • Railsのビューでは自動的にエスケープされる
  • SQLインジェクションを防ぐにはSQLエスケープしてから埋め込む
  • Railsではクエリメソッドに対してハッシュで条件を指定すると、自動的に安全化のための処理を行う

アセットパイプライン

  • アセットパイプラインはJavaScriptCSS、画像などのリソースを効率的に扱うための仕組み
  • アセットパイプラインによってコンパイルや複数のファイルを1つにまとめたりできる
  • production環境ではjsとcssのファイルを1つずつ生成し、高速化のためにアセットの連結と最小化が行われる
  • マニフェストファイルの//=はコメントではなく、アセットパイプラインに指示を伝えるための特別な行を表す

production環境

  • 開発環境と異なり、ユーザーが使いやすいようにパフォーマンスやエラー時の挙動を最適化する
  • Railsアプリは環境によって動作が微妙に異なる
  • production環境ではサーバを起動するときはrails assets:precompileで必ずプリコンパイルを実行する必要がある
  • 動的なコンテンツの配信に専念させるために、本番環境では静的ファイルの配信はwebサーバー担わせることが一般的
  • 本番環境用のデータベースを作成する必要がある
  • productionモードでアプリを利用する場合、production環境用の秘密情報を複合するための鍵の情報が必要になる

7章 機能を追加する

メール送信

  • RailsにはAction Mailerというメールを送るための仕組みが提供されている
  • メイラーはテンプレートを通じてメールを作成・送信する
  • rails g mailer [メイラー名]でメイラーを生成できる
  • メイラーにメールを送るためのメソッドを作成し、ビューにメールのテンプレートも作成し、コントローラでメイラーを呼び出しメソッドを実行することでメール送信の処理を実装する

ファイルのアップロード

  • RailsでファイルをアップロードするときにはActive Storageというgemが使われる
  • rails active_storage:installでActive Storageを使うための準備を行う

CSV

  • CSV形式のデータを扱うにはRubycsvライブラリを使う

ページネーション

  • データを複数のページに分割して表示するのがページネーション
  • ページネーションの実装にはkaminariというgemがよく使われる
  • デフォルトでは25件のデータが表示される
  • rails g kaminari:configでkaminariの設定ファイルを生成できる

非同期処理

  • Railsにはバックグラウンドで様々な処理を非同期に行うためのActive Jobというフレームワークが用意されている
  • ユーザーを待たせてしまうような重い処理は非同期処理として切り出すと良い
  • ジョブを生成し、バックグラウンドで実行したい処理を記述して、コントローラで呼び出す

8章 RailsJavaScript

Ajax

  • Ajaxによって画面遷移を行わずにサーバーのデータの取得や更新ができる
  • RailsAjaxを使うには、一からJavaScriptのコードを書く必要はなく、rails-ujsというライブラリを使用する
  • CoffeeScriptはJsを簡潔に書ける代替言語の1つで、Rails6からは標準では含まれない
  • Tubolinksとはページ遷移を自動的にAjax化することで高速化する仕組みで、Railsとは独立したライブラリ(Railsアプリを作成した時点で有効になっている)

Yarn

  • JavaScriptのパッケージマネージャ
  • npmより高速に動作し、ライブラリの予期せぬ変更を確認してくれるのでセキュリティが高い
    • Railsとは別でインストールする必要がある
  • Webpacker

  • Webpackのラッパーで、RailsでWebpackを使ったjsの管理を簡単にしてくれるgem
  • jsをES2015以降の記法で書くときや、ビルドプロセスをカスタマイズしたいときに使う
  • RailsとWebpackを組み合わせる設定が済んである

9章 複数人でRailsアプリケーションを開発する

  • チーム開発ではプロジェクトの概要や仕様、環境構築方法などをまとめたWikiなどのドキュメンテーションツールを使うことがある

コードレビュー

  • コードレビューではコードの問題点の指摘、他のやり方や懸念についての議論、意味・意図がわからない部分についての質問などを行う

CI

  • テストの実行には時間がかかるので、コードの変更ごとに自動テストを実行し、テストの失敗に気づけるようにCIツールを使う
  • CIツールをGithubと連携させることで、テストが通っているかどうかをプルリクエストの情報として見ることができ、問題のある変更を取り込むことを防げる

環境構築の構築方法をわかりやすくする

  • rails newの時点でbin/setupbin/updateが生成されている
  • bin/setupはセットアップの動作を記述したもの
  • bin/updateはgit pullを実行した後に環境を最新にするための動作を記述したもの

初期データを投入する

  • db/seeds.rbをbin/rails db:seedで初期・テスト用のデータを投入することができる

マイグレーション

10章 Railsアプリケーションと長く付き合うために

バージョンアップ

  • Railsだけでなく、Rubyやgem一式をバージョンアップさせる
  • バージョンアップには日常的に行うものと、準備して行うものの2つある
  • こまめにバージョンアップを行うことで、変更差分を確認しやすく、エラーが起きた時に元に戻しやすい
  • bundle installだとGemfile.lockのバージョンでインストールされるので、bundle updateを実行する
  • どのgemのバージョンがどう上がったのか確認し、妥当なバージョンか調査する
  • バージョンに問題がある場合は、バージョンを戻し固定する
  • 全てのgemをアップデートしたとしたらどうなるかのPull Requestを作るまではCIなどを使って自動化できる
  • 大きなバージョンアップでは、バージョンアップの作業と同時に機能の開発を進める方法と、バージョンアップをリリースしてから機能の開発を行う方法のどちらかを採用する

アプリの複雑性への対処

  • 複雑性への対処は、適切な場所にコードを書き、共通化し、新しい構造を追加して役割を分担させる
  • コントローラはViewとModelの複雑さが入り込みやすいので、肥大化しやすい
  • モデルの共通化
    • モジュールを使ってモデルクラスにMix-inする
    • クラスを継承させる
    • 全モデルに共通の処理をApplicationRecordに書く
  • コントローラの共通化はモデルとほぼ同じ
  • ビューの共通化
    • パーシャルテンプレートで画面の一部を共通化する
    • app/views/layoutsに新たなテンプレートを作成して画面の大枠を共通化させる
    • ビューのユーティリティメソッドであるカスタムヘルパーを使う