This page looks best with JavaScript enabled

『パーフェクトRuby on Rails』12章

 ·   ·  ☕ 3 分で読めます

12章

ユースケース

ユースケースとは、何らかの目的を達成するために行われる、ユーザーとアプリケーションの間の一連のやり取りを示したもの。

「GitHubアカウントでログインする」「イベントを登録する」などがユースケース。
「GitHubでログインボタンをクリックするとGitHubアプリケーション認証画面に遷移する」「イベント登録フォームで間違った入力をするとエラーメッセージが表示される」などがユーザーとアプリケーションの間のやり取り。

Webアプリケーションでは、HTTPを介してユーザーとアプリケーションのやり取りが行われる。
RailsはURLで表されるリソースをデータベースのテーブルと1対1に対応させており、これらのCRUD操作を通じてユーザーとやり取りをする。
1つまたは複数のCRUD操作によって1つのユースケースが構成される。
→1アクション1ユースケース。「あなた(ユーザー)が何かをしたら、わたし(アプリ)も何かをするよ」

Railsのレール

Railsでは、モデルのCRUD操作の前後に実行される処理を追加する(代表的なものがバリデーションとコールバック)ことでユースケースを実現している。
単純なアプリではデータベースとモデルとコントローラが(大体)1対1対1なのはそういうこと。

「同意する項目にチェックを入れているか検証する」「ユーザー登録が完了したらメールを送信する」などは、特定のユースケースに固有のものであり、ドメインロジックとは異なる種類のロジック。

しかーーーし、あるテーブルやデータ操作が複数のユースケースで行われるようになると、onとかifオプションを駆使することになってつらみが生まれる。
また、テーブルがないリソース(Cookieとか)のCRUD操作をすることも出てくる。

そんな問題を解決するために……
新しいレイヤーを導入してユースケースのロジックをモデルから分離する

ActiveModel

素のRubyクラスにActiveRecordと同様のインターフェースや機能を追加できる。
→データベースと紐付かないモデル

ActiveModel::Attributes

型をもつ属性の定義を容易にする。
自動で型変換が行われる。

1
2
3
4
5
6
class Person
  include ActiveModel::Attributes

  attribute :name, :string
  attribute :age, :integer, default: 10
end

ActiveModel::Callbacks

define_model_callbacks :saveでコールバック対象とするメソッドsaveを定義すると、before_save, around_save, after_saveが利用できる。
一部のみ使用する場合はonlyオプションを指定する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Person
  extend ActiveModel::Callbacks

  attr_accessor :created_at, :updated_at

  define_model_callbacks :save, only: %i[before]

  before_save :record_timestamp

  def save
    run_callbacks :save do  # run_callbacksで囲う必要がある
      true  # saveメソッドの中身
    end
  end

  private

  def record_timestamp
    current_time = Time.current

    self.created_at ||= current_time
    self.updated_at = current_time
  end
end

ActiveModel::Serialization

オブジェクトのシリアライズ機能。
オブジェクトをハッシュに変換するserializable_hashメソッドだけが提供される。

(省略)

ActiveModel::Validations

属性のバリデーションを容易にする。
データベースのレコードを参照するヘルパー以外はActiveRecordと同じものを使える。

before_validationを使用するためにはActiveModel::Validations::Callbacksのincludeも必要。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Person
  include ActiveModel::Validations
  include ActionModel::Validations::Callbacks

  attr_accessor :name, :age

  before_validation :normalize_name, if: -> { name.present? }

  validates :name, presence: true, length: { maximum: 100 }
  validates_numericality_of :age, greater_than_or_equal_to: 0

  private

  def normalize_name
    self.name = name.downcase.titleize
  end
end

ActiveModel::Model

ActiveModelが提供するモジュール群をひとまとめにしたもの。
コントローラやビューのメソッドとの連携に必要なインターフェースを提供する。

1
2
3
4
5
person = Person.new(name: "David")
app.url_for(person)
=> "http://www.example.com/people"
person.valid?
=> false

フォームオブジェクト

(以下省略。いつか書く)

Share on

aiandrox
Written by
aiandrox
今日も楽しく明日も楽しく

目次