LoginSignup
3
2

More than 5 years have passed since last update.

FactoryGirlでDRYを実践するためのtransient活用

Posted at

FactoryGirlで"Transient Attributes"(一時的な属性)の機能がスッキリ書くために便利だったので紹介します。

より詳しくはこちら

-
https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#transient-attributes
- FactoryGirlのtransientとtraitを活用する - Qiita

とにかく書いてみる例

FactoryGirl.define do
  factory :job_user, class: User do
    name "yamada(job_name)"
    sequence(:email) { |n| "job_name#{n}@example.com" }

    trait :programmer do
      name "yamada(programmer)"
      sequence(:email) { |n| "programmer#{n}@example.com" }
    end

    trait :architect do
      name "yamada(architect)"
      sequence(:email) { |n| "architect#{n}@example.com" }
    end

    trait :writer do
      name "yamada(writer)"
      sequence(:email) { |n| "writer#{n}@example.com" }
    end
  end
end

上記はuserの名前の後ろとメールアドレスにお仕事の英名を含むような仕様になっています。
見つめていると、DRY(Don't Repeat Yourself)に反しているような気がしてきます。
このような場合にTransient Attributesを使うことができます。

Transient Attributesを利用した例

job_nameという一時的なattributesを定義して、traitではjob_nameのみ差し替えるようにしました。

FactoryGirl.define do
  factory :job_user, class: User do
    transient do
      job_name "job_name"
    end
    name { "yamada(#{job_name})" }
    sequence(:email) { |n| "#{job_name}#{n}@example.com" }

    trait :programmer do
      job_name "programmer"
    end

    trait :architect do
      job_name "architect"
    end

    trait :writer do
      job_name "writer"
    end
  end
end
user = FactoryGirl.create(:job_user, :programmer)
user.name #=> "yamada(programmer)"

一時的なattributeのjob_nameのみ差し替えるようにしました。
この書き方があまり他に見当たらなくて、気づくまでtransient do...endをいちいち書いたりして余計見通しを悪くしていたりしました...。
だいぶスッキリしたのではないでしょうか。

また、次のように指定することも可能です。
もし繰り返して使うようなjob_nameがないのであれば、いっそtraitを無くしてこちらで対応しても良さそうです。

user = FactoryGirl.create(:job_user, job_name: "driver")
user.name #=> "yamada(driver)"

callbackでも使えるよ

callbackでも第2引数でtransientで指定したattributeを取得できます。

FactoryGirl.define do
  factory :job_user, class: User do
    transient do
      job_name "job_name"
    end
    name { "yamada(#{job_name})" }
    sequence(:email) { |n| "#{job_name}#{n}@example.com" }

    after(:create) do |user, evaluator|
      user.introduction ||= "私の仕事は#{evaluator.job_name}です"
    end
  end
end
user = FactoryGirl.create(:job_user, job_name: "driver")
user.introduction #=> "私の仕事はdriverです"

便利〜 :smile:

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2