パーフェクトRuby on Rails 読んでみた

part1:overview

ルーティング情報ファイルについて

config/routes.rb でモデルに対して CRUD 操作を定義している。

# config/routes.rb
Rails.application.routes.draw do
  resources :books
end

resources :books の部分で、 CRUD 操作を定義している。resources メソッドに :books を渡すことで CRUD 操作用のルーティングが設定される。

Active Recordとは

Active Record の理解が甘かったので、『Active Record の基礎 - Railsガイド』と、『パーフェクト Ruby on Rails』で内容を確認。

Active Recordとは、MVCで言うところのM(モデル)で、ビジネスデータとビジネスロジックを表すシステムの階層のことを言う。

Active Record の目的は、データベースに恒久的に保存される必要のあるビジネスオブジェクトの作成と利用を円滑に行えるようにすること。

Active Record は、『Patterns of Enterprise Application Architecture』という書籍にデザインパターンとして記されている。そこでは、『データアクセスのロジックを常にオブジェクトに含めておき、そのオブジェクトの利用者にデータベースへの読み書き方法を指示できるようにする』としている。

Active Record には多くの機能があるが、大きく2つの役割がある。

  • データベースと接続し、データベースのレコードと ActiveRecord オブジェクトを結びつける
  • バリデーションやレコード保存時などに実行する様々なコールバックなどを実行する

バリデーション(検証)とは

バリデーションは、Active Record を使って、モデルがデータベースに書き込まれる前に、モデルの状態を検証(バリデーション)することを言う。

Active Record にはモデルチェック用の様々なメソッドが用意されている。例えば、次のようなものがある。

  • 属性が空でないかどうか
  • 属性が一意かどうか
  • 既にデータベースにないかどうか
  • 特定のフォーマットに沿っているかどうか

『属性が空でないか』のバリデーションは、次のように書ける。下記は User モデルの name 属性が空でないかを検証する。

class User < ApplicationRecord
  validates :name, presence: true
end

注意としては、レースコンディションですり抜けてしまう問題もあり得るため、データベースで not null 制約などで設定する方がベター。

コールバックとは

コールバックは、オブジェクトのライフサイクル期間における特定の瞬間に呼び出されるメソッドのこと。

コールバックを利用することの旨味は次のもの。

  • 前処理、後処理などを宣言的に書ける
  • 保存後に必ず実行したい処理があるときに、実行漏れを防げる

つまり、コールバックは、オブジェクトの状態が切り替わる『前』または『後』に宣言したロジックをトリガする。

コールバックを利用する際の流れを次に示す。

  1. コールバックを登録する

    下記の before_validation がコールバックとなっていて、バリデーションの前に、before_validation として登録された ensusure_login_has_a_value メソッドをトリガする。

     class User < ApplicationRecord
       validates :login, :email, presence: true
    
       before_validation :ensure_login_has_a_value
    
       private
         def ensure_login_has_a_value
           if login.nil?
             self.login = email unless email.blank?
           end
         end
     end
    
  2. コールバックをトリガする

    コールバックの実行は、以下のメソッドを実行することによりトリガされる。

    • create
    • create!
    • destroy
    • destroy!
    • destroy_all
    • destroy_by
    • save
    • save!
    • save(validate: false)
    • toggle!
    • touch
    • update_attribute
    • update
    • update!
    • valid?

    after_find コールバックは以下の finder メソッドを実行すると呼び出される。

    • all
    • first
    • find
    • find_by
    • find_by_*
    • find_by_*!
    • find_by_sql
    • last

ビューのレンダリング

コントローラでモデルからデータ抽出や加工を行い、ビューでコントローラで取得したデータをユーザが認識可能な形式にレンダリングする。

レンダリングでは、render メソッドを使うことで、コントローラとビューを結びつける。

class BooksController < ApplicationController
  before_action :set_book, only: %i[show edit update destroy]
  ...
  # レンダリングを明示的に書く場合
  def show
    render :show
  end
  # レンダリングを暗黙的に書く場合
  def show; end # => 『render アクション名(show)』と解釈される
  ...
  def set_book
    @book = Book.find(params[:id])
  end
  ...

render :show の部分でレンダリングをしており、具体的には以下のことをする。

  • 描画するためのテンプレートを探索

    探索は、 RAILS_ROOT/app/views/コントローラ名/アクション名.html.erb に対して行われる。拡張子は使用するテンプレートエンジンによって異なる。

  • 見つかったテンプレートを基に、データを展開し最終的なHTMLを生成

上記の例では、ビューに渡すデータを before_action にて値をセットすることで、各ビューでデータを扱えるようにしている。

参考