ソニックの部屋

主にプログラミングに関する記事を投稿します

「現場で使える Ruby on Rails 5速習実践ガイド」を読む

気になった用語等をまとめる

第1章_RailsのためのRuby入門

学んだこと

  • オブジェクトの機能はクラスで決まる
  • 変数名はスネークケースで書く
  • レシーバとは「メソッドを持つオブジェクト」のこと
  • メソッドの途中で抜けたい場合はreturn、メソッドの最後で返り値を指定する場合は何も使わない
  • オブジェクト毎に異なるデータを保持したい場合はインスタンス変数を用いる
  • オブジェクトの抱えるデータのことを「属性」と呼ぶ
  • オブジェクトはインスタンス変数(データ)とメソッド(振る舞い)を抱える
  • Rubynilとfalseが偽
  • 処理が一行で済むケースは後置ifを使う
puts "hello" if true
  • キーワード引数はメソッド呼び出しをわかりやすくし、かつ、引数の順番を気にせず必要な部分だけを記述可能
def name(full: true, age: true)←キーワード引数にデフォルト引数も設定
...
...
person.name(age: false)←呼び出しがわかりやすく、かつ、必要な引数のみ記述
  • 子クラスのメソッドの中で親クラスの同名メソッドを呼びたい場合は「super」を使う
class BaseTask
  def puts_message
    puts "A"
  end
end

class Task < BaseTask
  def puts_message
    ** super **
    puts "B"
  end
end

>A
>B
  • モジュールは「部分的な設計書」でありクラスという設計書に共通の部分的な設計書を取り込むことで複数の似たクラスを簡単に実現できる
module Chatting
  def chat
    ...
  end
end

class Human
  ** include Chatting **
end

class Dog
  ** include Chatting **
end
  • フレームワーク独特の構文のように見えるものの多くがクラスメソッドとなっている
class Book < ApplicationRecord
  ** has_many :authors **
end
number | | = 10
# numberがnilの時にデフォルトで10を指定
  • %記法を使うと文字数が減り可読性が良くなることがある
ary1 = ["apple", "banana", "orange"]
ary2 = %w(apple banana orange)
# 上記は同じ意味
  • 配列の各要素から特定の属性だけを取り出す
class User
  attr_accessor :name
end

user1 = User.new
user1.name = "Alice"
user2 = User.new
user2.name = "Bob"
users = [user1, user2]

names = users.map(&:name)
# ["Alice", "Bob"]
# 「&:メソッド名のシンボル」により属性の取り出しが可能

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

学んだこと

  • Bundlerによりどのgemのどのバージョンを使うかを指定する
  • Bundler環境ではgemコマンドではなくBundler経由でgemを操作する
  • Railsサーバを起動してアプリにアクセスする際に「PG::ConnectionBad(could not connect to server:・・・)」というエラーが発生したらDBサーバが立ち上がっていないことが原因のため注意
  • MVCの流れ
    • まずはCが呼ばれる (ルーティングを実行)
    • Cにはリクエストに対する処理(アクション)がメソッドで定義されている
    • そのメソッドの中にMを定義する
    • MはDBとオブジェクト間のやり取りを隠蔽し外部から簡単にオブジェクトのデータをCRUDすることを可能にする
    • Vはブラウザに表示する画面を定義
  • ルーティングとはリクエストに対応するレスポンスを作るためにどの処理を実行するかを定義したもの (Cの中で機能する)
  • MVCとはソフトウェアをどのような構造にするかの考え方の一つ
  • MVCはUIに関わる部分(V)とアプリケーションに関わる部分(M)を分けて、VやMを制御するCにより管理しやすくしよう、というのが目的
  • ある機能をアプリに加える際は、まずその機能をどのCのどのメソッドで処理するかを決める
名称 役割
M ・オブジェクトとして実装
・DBへの保存や読み込みも担当
V ・HTTPレスポンスの中身を組み立てる
・CからMのオブジェクトを受け取り画面表示に利用する
C ・クライアントからのリクエストに応じて適切なレスポンスを返す
・MやVを利用してレスポンスを作る

第3章_タスク管理アプリを作ろう

学んだこと

railsコマンド 内容
rails new アプリ名 -d postgresql ・アプリケーションの雛形と作成
・-dでDBを指定
bin/rails db:create DBの作成
bin/rails s サーバの起動
bundle Gemfileに記述した「gem "xxx"」をインストール
bin/rails g model [モデル名] [属性名:データ型] モデルの作成(+マイグレーションファイルの作成)
bin/rails g migration 名前 マイグレーションファイルの作成
bin/rails db:migrate テーブルの作成
bin/rails g controller [コントローラ名] [アクション名] コントローラとビューの作成(+ルーティングの作成)
  • 1つの環境(開発、テスト、本番)に対して1つのDBを対応させる
  • これはconfig/database.ymlで設定する
  • Vを効率良く書くためにSlimを使う
  • CSSを効率良く書くためにSassを使う
  • Railsはアプリ全体で「application.css」を読み込み、他のCSSファイルは「application.css」をさらに読み込む形で記述する
  • Mはクラスとテーブルから構成される
    • クラス名はキャメルケース、テーブル名はスネークケース
    • テーブル名はクラス名の複数形
    • Mの属性はテーブルのカラムに対応
  • M, V, Cはいずれもジェネレータで雛形の作成が可能(rails g ~)
  • アクションの機能
    • アクションからVに受け渡しをしたいデータをインスタンス変数に入れる
    • ブラウザに返す画面をどうするかを記述する (省略した場合はアクション名に対応する画面を表示)
  • リクエストパラメータとはリクエストに添えたデータのこと
  • Cでparamsというメソッドを用いてPOSTかGETに関係なくリクエストパラメータを取得する
  • レンダーとリダイレクト
    • レンダーはアクションの直後にVを表示させる(1つのリクエスト)
    • リダイレクトはアクションの直後に別のURLに案内させる(2つのリクエスト)
  • 何も記述しないとアクションに対応する場所・名前のVファイルをrenderする
  • redirect_toにはFlashメッセージ(次のリクエストにデータを渡す)を渡すことができる
redirect_to tasks_url, notice: "タスクを登録した"
# 「notice: "タスクを登録した"」がFlashメッセージ
  • 共通部分はrenderメソッドのパーシャルテンプレートを使う
V内に、「_form.html.slim」を作る
# パーシャルテンプレートには_を付ける
  • rails5ではJavaScriptをサポートするためのライブラリが異なる
  • つまり、rails5ではrails-ujsを使用していたが、rails7からはtuboとなっている
変更前:
= link_to "削除", task, method: :delete, data: { confirm: "タスク「#{task.name}」を削除します。よろしいですか?" }, class: "btn btn-danger"

変更後:
= link_to "削除", task, data: { turbo_method: :delete, turbo_confirm: "タスク「#{task.name}」を削除します。よろしいですか?" }, class: "btn btn-danger"

第4章_現場の複雑さに対応する(制限、検証、コールバック、フィルタ、ログイン機能追加、関連、検索)

学んだこと

マイグレーション

カラムの「制限」

  • カラムにはデータ型、NOT NULL制約、長さの指定、ユニークインデックスで制限をかける
  • テーブル作成時、作成後に制限をかける

モデルの「検証」

  • saveメソッドでDBの登録・更新を行う前に検証を行い、エラーがあればfalseを返す
  • valid?メソッドで検証処理を単独で行う(DB関係なし)
  • バリデーションのエラーメッセージが表示されない時は参考文献①参照
  • saveなどの登録・更新系のメソッドは自動的にバリデーション機能を持つ

モデルの状態を制御する「コールバック」

  • コールバックは「然るべきタイミングが来たらこの処理を呼んで下さい」
  • モデルオブジェクトの重要なイベント(登録・更新等)の前後に任意の処理を組み込む(コールバック)

ログイン機能

  • セッションとは一つのブラウザから連続して送られている一連のリクエストの間で「状態」を共有できるようにする仕組み
  • Cからsessionメソッドを呼び出すことでセッションにアクセスする
  • クッキーとは複数のリクエストの間で共有したい「状態」をブラウザ側に保存する仕組み
  • セッションの仕組みの一部がクッキーによって実現されている点がポイント(クッキーの中のセッションIDにより状態を維持)
  • ブラウザ側でクッキーを消すとセッションもリセットされる
  • ログイン機能はログインをする=「セッションを作る」と捉えてSessionsControllerという名前でCを作る
  • Cの「フィルタ」でログインしていなければ利用できないようにする
  • 「関連」によりDB上の紐付けを前提にモデルクラス同士の紐付けを定義

データを絞り込む

  • DBデータの絞り込むは3点意識
    • 1、起点
    • 2、絞り込み状況
    • 3、実行部分
User.where(admin:true).fisrt
# 左から1、2、3
# adminカラムにtrueの入っているUserの内最初に見つかったものを取得

scopeを活用する

  • scopeにより繰り返し利用される絞り込み条件(上記2、の部分)をまとめられる

フィルタにより重複を避ける

  • 上記のフィルタを使う

URLをリンクとして表示する

  • gemのrails_autolinkを使う

第5章_テストをはじめよう

学んだこと

  • 自動テストは環境のバージョンアップやリファクタリングの必須条件
  • テストのツールは色々ありRSpecがよく使われる
# RSpecの基本の書き方
describe [テスト対象], type: [テストの種類] do
  context [ある状況] do
    before do
      [事前準備]
    end

    it [仕様] do
      [期待する動作]
    end
  end

end
# テストケースを整理する:describe, context
# テストケースを実行する:before, it
  • 画面に特定の内容が存在することを検査
it { expect(page).to have_content "最初のタスク" }
# 最初のタスクが画面にあることを期待する
# 「have_content "最初のタスク"」部分をマッチャという
  • letで先に処理される外側に共通処理を書き、内側の複数のdescribe/contextごとに細かい違い部分を書く

第6章_Railsの全体像を理解する

学んだこと

  • ルーティングのresources :tasks
一覧:GET /tasks
詳細:GET /tasks/:id
など典型的なCRUD7つのパターンを一括定義
  • 日時はデフォルトではUTC
  • ログレベルは設定可
  • ストロングパラメーターはCでリクエストパラメーターを受け取る際に想定通りのパラメーターかホワイトリスト形式でチェックする
params.require(:task).permit(:name, :description)
  • アセットパイプラインはjs, css, 画像等を効率的に扱う仕組み
  • Sprocketsが使われている

第7章_機能を追加してみよう

学んだこと

登録や編集の実行前に確認画面を表示

  • 意外に手間なので本当に必要か要確認

一覧画面に検索機能を追加する

  • Ransackのインストール
gem "ransack"

# taskモデルに手動で追加
def self.ransackable_attributes(auth_object = nil)
    ["created_at", "description", "id", "name", "updated_at", "user_id"]
  end

メールを送る

  • アクションメイラーの作成
bin/rails g mailer TaskMailer
  • mailchatcherのインストール
# smtpサーバーを立てて送信メールをブラウザ上で確認できる
# Gemfileに書くとエラーとなるためローカルでインストール(参考文献②)
gem install mailcatcher

ファイルアップロード+モデルに添付

  • アクティブストレージの準備
bin/rails active_storage:install
# 2つのテーブル(active_storage_blobs, active_storage_attachments)が作成される
  • active_storage_blobsはファイルをデータベース外で管理する
  • active_storage_attachmentsはactive_storage_blobsと他モデルを関連付ける中間テーブル

CSVファイルの取り扱い

  • config/application.rbに追記
require "csv"
  • M, V, Cの設定が必要

ページネーション

  • kaminariのインストール
gem "kaminari"
  • V, C(index)の設定が必要
  • デフォルトの表示件数は1ページ25件(調整する場合は設定ファイルを作成する)
bin/rails g kaminari:config
  • 見栄えの調整
bin/rails g kaminari:views bootstrap4

非同期処理と定期実行(jobスケ)

brew install redis
# サーバーの起動
redis-server

gem 'sidekiq', '~> 5.0' ※最新のものはエラーになる(参考文献③参照)
gem "listen" ※これがないとエラーになる
# サーバーの起動
bundle exec sidekiq
  • jobの実行はjob雛形を作成し記述する
bin/rails g job sample
  • jobの実行日時の指定も可能

第8章_RailsJavaScript

学んだこと

  • Railsでアプリの基本的な機能を実装し、JSで画面遷移なしの動作を実装する
  • DOMはHTMLをJS等のプログラムから利用するための仕組み
  • イベントハンドラはイベントが発生した時に呼び出される処理
  • Ajaxはブラウザ上で非同期通信を行いページの再読み込みなしにページを更新する
  • 削除はサーバー側で非同期で削除してフロント側で非表示にする
  • Turbolinksはページ遷移を高速化する
  • Turbolinksを利用する時のscriptはhead要素に書く
  • バグやエラーを避けるためにTurbolinksを無効化するのもあり
  • YarnとWebpackerでJSを構造化して大規模アプリ開発をする
  • Yarnはパッケージマネージャー(npmより高速)
# Yarnのインストール
サイトを参考に
bin/以下にyarnファイルを格納する

# パッケージの追加
bin/yarn add パッケージ名

# package.jsonに記述されたパッケージを一括インストール
bin/yarn install
  • WebpackerはライブラリでアセットパイプラインのSprocketsをサポートする
  • WebpackerとSprocketsの併用は管理が煩雑になるので非推奨
  • Webpackerの利用にはYarnのインストールが必須
gem "webpacker"
bin/rails webpacker:install
  • Reactのインストール
bin/yarn add react react-dom

# エラーが起きたのでpackage.jsonファイルのdevDependenciesに以下追加
"devDependencies": {
  "@babel/plugin-proposal-private-property-in-object": "^7.0.0"
}

その後yarn install

第9章_複数人で開発

学んだこと

  • railsアプリを作成すると自動的に.gitignoreファイルが作成され不要なファイルが選別される
  • ローカルで作業ブランチを切って作業をした後にmainにマージする手順は二つ
    • 作業ブランチをmainの最新にrebase
    • mainを作業ブランチにマージ
  • 作業ブランチで(git getch, git rebase 作業ブランチ)git rebase main
  • mainでgit pullの後に作業ブランチでgit merge main
  • push -fで強制的にローカルの内容をリモートに反映させる
  • seedで初期データを登録
# db/seeds.rb
bin/rails db:seed
# バージョンを下げて問題なければ上げる
bin/rails db:migrate:redo

第10章_Railsアプリと長く付き合う

学んだこと

  • Gemifileに記述されたバージョンの範囲内でbundle updateが行われる
  • コントローラーは複雑になりがちなのでモデルに寄せることを考える
  • モジュールを作って複数のモデル・コントローラーからincludeする、その他継承やApplicationRecordへの記述により共通化する
  • ビューはパーシャルテンプレートやカスタムヘルパーで共通化
  • ActiveModel等で整理
  • コードがわかりづらくなるためモジュールの利用しすぎに注意
  • アップデートと複雑性への対応が必須

最後に

良かったところ

  • Railsの基本的な仕組みがわかった

悪かったところ(もしあれば)

  • Railsのバージョンが古く何箇所も修正が必要なところ

難しかったこと

  • 何回もインプットしないと分からない所が多くアウトプットして覚えていく

他参考ブログ記事

Rails基礎

参考文献
現場で使える Ruby on Rails 5速習実践ガイド
大場寧子 (著), 松本拓也 (著), 櫻井達生 (著), 小田井優 (著), 大塚隆弘 (著), 依光奏江 (著), 銭神裕宜 (著), 小芝美由紀 (著)/マイナビ出版/2018

①@P-man_Brown, 2023/10/10取得, 【Rails】Rails7.0でバリデーションのエラーメッセージが表示されない時の解決法
Github, 2023/10/14取得, Mailcatcher crashing #76
③@SyoInoue(井上 翔), 2023/10/15取得, 【Rails】NameError: uninitialized constant Sidekiq::Loggingの解決方法【非同期処理】