Railsを学ぶために「現場で使えるRuby on Rails5速習実践ガイド」を読んで、写経しました。
感想
今までWebやLinux、Ruby、SQLなどを学んできて、ようやく実際のアプリを作っていく段階までこれました。 一通り本を読んで写経しましたが、Railsっていうかフレームワークってすげーって感じです。いろんな機能をちょこっとコードを書くだけで実装できました。
Railsの基本的な内容が主ですが、かなり実践的だと思います。Railsの話だけでなく、フロント側のJavaScriptや、テスト、チーム開発の進め方など、Railsに関わる全般的な内容を網羅しています。 かなり内容が濃く、写経にも時間がかかったので、何周もやるよりはさっさとアウトプットして理解を進める方が早いと思います。特に10章はリファクタリング的な内容でもあるので、アプリを作れるようになってからじゃないと身につかないと思います。
書籍ではrbenvを使って環境構築を行うのですが、Dockerを使って環境構築を行いました。ただしDockerだとブラウザテストやメール送信、非同期処理などが書籍通りの設定ではできないため、そこの設定に詰まりました。 あと本番環境のデータベースの作成でも詰まって解決しなかったので、一旦置いておいて実際にアプリを作った時にもう一度読み直そうと思います。
様々なgemを使うので、それぞれのドキュメントを見たり、よく使われるgemを把握しておこうと思います。
新しく学んだこと
細かい実装方法までは記述せず、インデックスを作る感じでまとめておきます。
2章 Railsアプリケーションをのぞいてみよう
- rbenvでRubyのバージョンを切り替えることができる
rails generate scaffold user
でユーザーに関するscaffoldを自動生成できるMVCの処理の流れ
- URLにアクセスする
- コントローラが呼ばれ、リクエストに対するアクションメソッドが実行される
- データを扱うときはモデルを呼び出す
- 画面を表示するためにビューが呼び出される
オブジェクトと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つ
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_many
やbelongs_to
などを記述する
データを絞り込む
- データを絞り込んで検索等を行うときは、何からどんな条件で絞り込んでどう実行するかを意識する
- クエリー用のメソッドは実行部分に当たるメソッドを呼ぶことで実行される
scope
- scopeを使うことで、検索条件を定義して繰り返し使えるようにできる
5章 テストをはじめよう
テストのメリット
- コードの新しい変更によってエラーが起きないか自動的にチェックできるので気軽に変更できる
- バージョンアップやリファクタリングを行いやすい
- テストによってメソッドがどんな振る舞いをするか読み取ることができる
- テストをアプリの仕様として扱える
- テストを書きやすいようにコードを書くと管理しやすいコードになる
RSpec
- 動く仕様書として自動テストを書くという発想で作られたテスティングフレームワーク
- 準備
- 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を設定する
日時
- 地域のタイムゾーンに合わせた日時を表示する必要がある
- Timeの代わりに
ActiveSupport::TimeWithZone
クラスを使う - UTCは協定世界時のタイムゾーンを表す
- 起動時のタイムゾーンは
config/application.rb
のconfig.time_zone
で指定する
エラー処理
- 環境ごとの設定ファイルの
config.consider_all_requests_local
がtrueの時にデバッグ用、falseで本番用のエラー画面が表示される - デフォルトでは404、422、500のエラー画面が用意されている
ログ
- Railsのサーバーを起動しているとログが出力される
- ログは
log/development.log
にも出力される - 自分でログを出力させたい時は
logger
オブジェクトを使う - デフォルトのログレベルがdebugなので、すべてのログレベルが出力される
- ログに出力したくない値は
config/initializers/filter_parameter_logging.rb
のRails.application.config.filter_parameters
に設定する
セキュリティ
- Railsには標準でセキュリティを高める機能が備わっているのである程度は意識する必要はない
- リクエストを偽造してユーザーがログインしているアプリに悪意ある操作を行う攻撃がCSRF
- Railsの場合、アクセスしているのがユーザー本人かはCookieを利用したセッションで判断する
- CSRFは同じアプリからのリクエストであることを証明するセキュリティトークンを発行して照合することで対策する
- Railsの提供している
form_with
などを使うとセキュリティトークンの仕組みが自動的に作られる - インジェクションはアプリに悪意のあるスクリプトや値が入力される攻撃
- XSSの対策は危険なHTMLタグをそのまま解釈しないようにエスケープする
- Railsのビューでは自動的にエスケープされる
- SQLインジェクションを防ぐにはSQLをエスケープしてから埋め込む
- Railsではクエリメソッドに対してハッシュで条件を指定すると、自動的に安全化のための処理を行う
アセットパイプライン
- アセットパイプラインはJavaScript、CSS、画像などのリソースを効率的に扱うための仕組み
- アセットパイプラインによってコンパイルや複数のファイルを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
ページネーション
- データを複数のページに分割して表示するのがページネーション
- ページネーションの実装にはkaminariというgemがよく使われる
- デフォルトでは25件のデータが表示される
rails g kaminari:config
でkaminariの設定ファイルを生成できる
非同期処理
- Railsにはバックグラウンドで様々な処理を非同期に行うためのActive Jobというフレームワークが用意されている
- ユーザーを待たせてしまうような重い処理は非同期処理として切り出すと良い
- ジョブを生成し、バックグラウンドで実行したい処理を記述して、コントローラで呼び出す
8章 RailsとJavaScript
Ajax
- Ajaxによって画面遷移を行わずにサーバーのデータの取得や更新ができる
- RailsでAjaxを使うには、一からJavaScriptのコードを書く必要はなく、
rails-ujs
というライブラリを使用する - CoffeeScriptはJsを簡潔に書ける代替言語の1つで、Rails6からは標準では含まれない
Tubolinks
Yarn
- JavaScriptのパッケージマネージャ
- npmより高速に動作し、ライブラリの予期せぬ変更を確認してくれるのでセキュリティが高い
- Railsとは別でインストールする必要がある
Webpacker
- Webpackのラッパーで、RailsでWebpackを使ったjsの管理を簡単にしてくれるgem
- jsをES2015以降の記法で書くときや、ビルドプロセスをカスタマイズしたいときに使う
- RailsとWebpackを組み合わせる設定が済んである
9章 複数人でRailsアプリケーションを開発する
- チーム開発ではプロジェクトの概要や仕様、環境構築方法などをまとめたWikiなどのドキュメンテーションツールを使うことがある
コードレビュー
- コードレビューではコードの問題点の指摘、他のやり方や懸念についての議論、意味・意図がわからない部分についての質問などを行う
CI
- テストの実行には時間がかかるので、コードの変更ごとに自動テストを実行し、テストの失敗に気づけるようにCIツールを使う
- CIツールをGithubと連携させることで、テストが通っているかどうかをプルリクエストの情報として見ることができ、問題のある変更を取り込むことを防げる
環境構築の構築方法をわかりやすくする
- rails newの時点で
bin/setup
とbin/update
が生成されている bin/setup
はセットアップの動作を記述したものbin/update
はgit pullを実行した後に環境を最新にするための動作を記述したもの
初期データを投入する
- db/seeds.rbを
bin/rails db:seed
で初期・テスト用のデータを投入することができる
マイグレーション
- マイグレーションでトラブルが起きると、他の作業を進められなくなるので注意
db:migrate:redo
でロールバックができることを確認しておく- 過去のマイグレーションファイルを変更するより、新しいマイグレーションファイルを作成する
- 基本的にデータベースは手作業ではなくマイグレーションで変更する
10章 Railsアプリケーションと長く付き合うために
バージョンアップ
- Railsだけでなく、Rubyやgem一式をバージョンアップさせる
- バージョンアップには日常的に行うものと、準備して行うものの2つある
- こまめにバージョンアップを行うことで、変更差分を確認しやすく、エラーが起きた時に元に戻しやすい
bundle install
だとGemfile.lockのバージョンでインストールされるので、bundle update
を実行する- どのgemのバージョンがどう上がったのか確認し、妥当なバージョンか調査する
- バージョンに問題がある場合は、バージョンを戻し固定する
- 全てのgemをアップデートしたとしたらどうなるかのPull Requestを作るまではCIなどを使って自動化できる
- 大きなバージョンアップでは、バージョンアップの作業と同時に機能の開発を進める方法と、バージョンアップをリリースしてから機能の開発を行う方法のどちらかを採用する