FactoryGirlで"Transient Attributes"(一時的な属性)の機能がスッキリ書くために便利だったので紹介します。
より詳しくはこちら
とにかく書いてみる例
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です"
便利〜