FactoryBot Traits

[FactoryBot](https://github.com/thoughtbot/factory_bot) はフィクスチャのツールです。
多くのフィクスチャを必要とするときは [Traits](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#traits) が便利です。 

# Setup

[Ruby on Rails](http://rubyonrails.org/) に [RSpec](http://rspec.info/) のテスト環境を構築して確認しましょう。
今回はコンソールモードで確認します。`spec/factories` のファイルを修正するとコンソールで `FactoryBot.reload` を実行してください。

```bash
mkdir factory_bot_rails_example && cd factory_bot_rails_example/ && rails new . --api -BT
echo "gem 'pry-rails', group: [:development]" >> Gemfile
echo "gem 'factory_bot_rails', group: [:development, :test]" >> Gemfile
echo "gem 'rspec-rails', group: [:development, :test]" >> Gemfile
bundle
bundle exec rails generate rspec:install
rails generate model product title vendor state 
rails console
```

# Usage

## Trait

`trait`は項目をグループにすることができます。

```ruby
FactoryBot.define do
  factory :product do
    title 'iPad'

    trait :modify do
      title 'iPhone'
    end
  end
end
```

フィクスチャにするにはトレイトのシンボルを第2引数に指定します。

例では、シンボルに`modify`を指定すると`title`が`iPad`から`iPhone`に変更されます。

```ruby
[1] pry(main)> FactoryBot.reload
[2] pry(main)> FactoryBot.attributes_for(:product)
=> {
    :title => "iPad"
}
[3] pry(main)> FactoryBot.attributes_for(:product, :modify)
=> {
    :title => "iPhone"
}
```

## Traits

`traits`で`trait`をまとめることができます。

```ruby
trait :base do
  vendor 'Apple'
end

trait :activate do
  state :active
end

factory :product_activate, traits: [:base, :activate]
```

トレイトのシンボルをは引数に複数を指定できます。また、`traits`は第1引数にシンボルを指定します。

例では、同じ値が出力されています。フィクスチャにラベルが付いて便利ですね。

```ruby
[4] pry(main)> FactoryBot.reload
[5] pry(main)> FactoryBot.attributes_for(:product, :base, :activate)
=> {
     :title => "iPad",
    :vendor => "Apple",
     :state => :active
}
[6] pry(main)> FactoryBot.attributes_for(:product, :base, :activate)
=> {
     :title => "iPad",
    :vendor => "Apple",
     :state => :active
}
```

## Transient

`transient`は内部で利用する変数ですが、`trait`と組合せて利用することができます。

```ruby
transient do
  time true
end

trait :cancel do
  state :canceled
  canceled_at { Time.now if time }
end

factory :product_cancel, traits: [:base, :cancel]
```

`trait`のブロッブのブロックはある程度は自由なエリアです。 (夢が広がりますね。

例では、`time`変数で`canceled_at`のセットを制御しました。

```ruby
[7] pry(main)> FactoryBot.reload
[8] pry(main)> FactoryBot.attributes_for(:product_cancel)
=> {
          :title => "iPad",
         :vendor => "Apple",
          :state => :canceled,
    :canceled_at => 2018-02-22 22:22:22 +0900
}
[9] pry(main)> FactoryBot.attributes_for(:product_cancel, time: false)
=> {
          :title => "iPad",
         :vendor => "Apple",
          :state => :canceled,
    :canceled_at => nil
}
```

# Tips

`factory`の引数には`traits`やブロック(`do``end`)などを指定できます。
(`traits`のブロックは1項目なら`{}`で1行で記述できます。)

```ruby
factory :product_ipod_touch, traits: [:base, :activate] do
  title 'iPod touch'
end
```

`traits`とブロックでフィクスチャをスッキリと管理することができます。 (ｷﾘｯ

```ruby
[10] pry(main)> FactoryBot.reload
[11] pry(main)> FactoryBot.attributes_for(:product_ipod_touch)
=> {
     :title => "iPod touch",
    :vendor => "Apple",
     :state => :active
}
```

# Example

紹介したサンプルはこちらです。

```ruby
FactoryBot.define do
  factory :product do
    title 'iPad'

    trait :modify do
      title 'iPhone'
    end

    transient do
      time true
    end

    trait :base do
      vendor 'Apple'
    end

    trait :activate do
      state :active
    end

    trait :cancel do
      state :canceled
      canceled_at { Time.now if time }
    end

    factory :product_activate, traits: [:base, :activate]
    factory :product_cancel, traits: [:base, :cancel]

    factory :product_ipod_touch, traits: [:base, :activate] do
      title 'iPod touch'
    end

    factory :product_ipod_nano,    traits: [:base, :activate] { title 'iPod nano' }
    factory :product_ipod_shuffle, traits: [:base, :activate] { title 'iPod shuffle' }
    factory :product_ipod_classic, traits: [:base, :activate] { title 'iPod classic' }
  end
end
```