【要約】Rails4でエンタープライズなActiveRecordモデルを作るための6のステップ

詳しくはブログ記事の「[Rails4でエンタープライズなActiveRecordモデルを作るための6のステップ](http://blog.enogineer.com/2014/10/26/enterprise-active-record/)」にまとめたので、Qiitaには要約(というかほとんどコード)をまとめておきます。

くわしくは[ブログ記事](http://blog.enogineer.com/2014/10/26/enterprise-active-record/)の方をご覧ください。

## 1. モデルは階層化する

    $ rails g model Blog::User name:string profile:text
    $ rails g model Blog::Post user:references permalink:string title:string content:text

## 2. DB制約を追加する

```rb
class CreateBlogPosts < ActiveRecord::Migration
  def change
    create_table :blog_posts do |t|
      t.references :user, index: true, null: false
      t.string :permalink, null: false, limit: 64
      t.string :title, null: false, limit: 128
      t.text :content, null: false

      t.timestamps
    end

    add_index :blog_posts, :permalink, unique: true

    add_foreign_key :blog_posts, :blog_users, column: :user_id
  end
end
```

## 3. validationを追加する

```rb
class Blog::Post < ActiveRecord::Base
  belongs_to :user

  validates :permalink, presence: true, uniqueness: true, length: {maximum: 64}
  validates :title, presence: true, length: {maximum: 128}
  validates :content, presence: true
end
```

## 4. FactoryGirlを定義する

```rb
FactoryGirl.define do
  factory :blog_post, class: 'Blog::Post' do
    user
    sequence(:permalink) { |n| "permalink_#{n}" }
    title "title"
    content "content"
  end
end
```

## 5. カスタムマッチャを追加する

[Rails4のモデル用カスタムマッチャ](http://blog.enogineer.com/categories/model-spec-custom-matchers/)の以下のカスタムマッチャを追加します。

**[have_not_null_constraint_onマッチャ](http://blog.enogineer.com/categories/model-spec-custom-matchers/)**
データベースのNOT NULL制約をテストします

**[have_unique_constraint_onマッチャ](http://blog.enogineer.com/2014/09/08/rspec-db-not-null-constraint/)**
データベースのUNIQUE制約をテストします

**[have_foreign_key_constraint_onマッチャ](http://blog.enogineer.com/2014/09/10/rspec-db-foreign-key-constraint/)**
データベースの外部キー制約をテストします

**[create_modelマッチャ](http://blog.enogineer.com/2014/10/26/rspec-create-model-matcher/)**
FactoryGirlでのモデル生成をテストします

**[safely_validate_uniqueness_ofマッチャ](http://blog.enogineer.com/2014/10/26/rspec-safely-validate-uniqueness-of-matcher/)**
InvalidForeignKeyエラーにならないようにuniqueness validationをテストします

## 6. FactorGirl, Association, Validation, DB制約をテストする

```rb
describe Blog::Post, type: :model do
  subject { build(:blog_post) }

  context 'with FactoryGirl' do
    it { should create_model }
    it { should create_model.for(2).times } #uniqueなオブジェクトを生成することを確認
  end

  context 'with associations' do
    it { should belong_to(:user) }
  end

  context 'with validations' do
    it { should validate_presence_of(:user_id) }
    it { should validate_presence_of(:permalink) }
    it { should validate_presence_of(:title) }
    it { should validate_presence_of(:content) }

    it { should ensure_length_of(:permalink).is_at_most(64) }
    it { should ensure_length_of(:title).is_at_most(128) }

    it { should safely_validate_uniqueness_of(:permalink) }
  end

  context 'with DB' do
    it { should have_not_null_constraint_on(:user_id) }
    it { should have_not_null_constraint_on(:permalink) }
    it { should have_not_null_constraint_on(:title) }
    it { should have_not_null_constraint_on(:content) }

    it { should have_unique_constraint_on(:permalink) }

    it { should have_foreign_key_constraint_on(:user_id) }
  end
end
```