中／大規模開発のためのRails設計パターン

# 概要
`app`ディレクトリ以下のファイル構成は下記のようにします。

```
$ tree app/ -d -L 1
app
├── callbacks
├── controllers
├── decorators
├── exceptions
├── factories
├── models
├── policies
├── services
├── tasks
├── utils
├── validators
├── values
└── views
```

# クラス設計
## Callback
クラス名の命名規則として、接尾辞に**Callback**を付与します。
ActiveRecordのコールバック処理をまとめます。

- after_find
- after_initialize
- before_validation
- after_validation
- before_save
- before_create / before_update
- after_create / after_update
- after_save
- after_commit
- after_rollback
- after_touch
- before_destroy
- after_destroy

```ruby:app/callbacks/user_callback.rb
class UserCallback
  def before_create(user)
    user.name = default_name(user)
  end

  private

  def default_name(user)
    user.email.split('@').first
  end
end
```

```ruby:app/models/user.rb
class User < ActiveRecord::Base
  before_create UserCallback.new
end
```

## Controller
クラス名の命名規則として、接尾辞に**Controller**を付与します。
*Controller*の仕事としては、

- パラメーターやセッションの状態
- Validation結果による処理の分岐
- テンプレートの出し分け

に留めて、具体的なビジネスロジックについては
後述する*Service*, *Validator*等に任せます。

## Decorator
クラス名の命名規則として、接尾辞に**Decorator**を付与します。
*Model*と*View*の中間に位置し、*Model*や*View*に実装されやすい表示ロジック／フォーマットといったプレゼンテーション層の責務を引き受けます。
[Draper](https://github.com/drapergem/draper)というgemを使用すると扱いやすいです。

```ruby:app/decorators/article_decorator.rb
class ArticleDecorator < Draper::Decorator
  def published_at
    object.published_at.strftime("%A, %B %e")
  end
end
```

```ruby:app/controllers/article_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = ArticlesDecorator.decorate(Article.all)
  end
end
```

## Exception
クラス名の命名規則として、接尾辞に**Error**を付与します。
例外を使う場合に`raise`に文字列を渡すのではなく、
ここに`StandardError`を継承したカスタム例外クラスを実装して、それを使うようにします。

## Factory
クラス名の命名規則として、接尾辞に**Factory**を付与します。
*Factory*では主に以下の3種類の処理を行います。

- 複数のオブジェクトから単一のデータオブジェクトの生成
- データ構造を持たないデータからデータオブジェクトの生成
- 共通のインターフェースを持つオブジェクトの透過的生成

## Model
Modelには

- association
- scope
- enum
- データベースレベルでの制約(not null, unique等)に関するvalidation
- 状態の取得、変更

に関するメソッド**のみ**記述するのが良いです。
ビジネスロジックはここで実装してはいけません。

## Policy
クラス名の命名規則として、接尾辞に**Policy**を付与します。
[Pundit](https://github.com/varvet/pundit)などを使って、認可に関する処理をここで実装します。

```ruby:app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
  def update?
    user.admin?
  end
end
```

## Service
クラス名の命名規則として、接尾辞に**Service**を付与します。
特に理由がなければ、基本的に「動詞(+目的語)+Service」という名前のクラス(例:**CreateUserService**)で、
**call**という名前のクラスメソッドのみを公開します（private methodは自由です）。
（参考 : [Rails のサービスクラスでのマイルールとちょっとしたコツ](http://qiita.com/QUANON/items/5ef803988c0ad6930e4b)）
専門性の高い処理はここで実装します。
DBのトランザクションはこのレイヤーで管理するようにします。

```ruby:app/services/create_user_service.rb
class CreateUserService
  def call
    User.create!
  end
end
```

## Task
クラス名の命名規則として、接尾辞に**Task**を付与します。
`rake task`の実処理を記述します。
rakeファイルには*Task*へのパラメーター受け渡しのみを記述し、実際の処理は*Task*に記述します。

## Util
クラス名の命名規則として、接尾辞に**Util**を付与します。
複数のクラスから共通で使われる汎用的な(=専門性の低い)処理をまとめます。

## Validator
クラス名の命名規則として、接尾辞に**Validator**を付与します。
独自バリデーションを実装する際にはここに置きます。

```ruby:app/validators/user_validator.rb
class UserValidator < ActiveModel::Validator
  def validate(record)
    unless record.email.include? '@'
      record.errors[:email] << 'Should include @ in email'
    end
  end
end
```

```ruby:app/models/user.rb
class User < ActiveRecord::Base
  include ActiveModel::Validations
  validates_with UserValidator
end
```

## Value
オブジェクト指向で言うバリューオブジェクトをここに置きます。
[Date](https://docs.ruby-lang.org/ja/latest/class/Date.html)や[URI](https://docs.ruby-lang.org/ja/latest/class/URI.html)などが、Rubyの標準ライブラリのバリューオブジェクトになります。
特に下記の特性があるものを*Value*として実装します。

- 保持した値は決して変更されることがない
- オブジェクトを識別する一意となる値を保持していない
- 全プロパティ値が同じなら、同じオブジェクトである
- ActiveRecordのプロパティに使用する

下記は、学生の成績を管理するバリューオブジェクトの例です。

```ruby:app/values/rating.rb
class Rating
  include Comparable

  attr_accessor :score

  def initialize(score)
    @score = score
  end

  def <=>(other)
    @score - other.score
  end

  def to_s
    case @score
    when 0..59
      'F'
    when 60..69
      'C'
    when 70..79
      'B'
    when 80..89
      'A'
    else
      'A+'
    end
  end
end
```

```ruby:app/models/student.rb
class Student < ActiveRecord::Base
  def rating
    @rating ||= Rating.new(score)
  end
end
```

## View
いわゆるビューです。