Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby: FactoryBotでglobalに使えるtraitを定義するMEMO

以下の記事を追記するときにFactoryBotでfactory跨いで使いたいtraitを定義する方法調べていて見つけたのでMEMOしておきます📝

madogiwa0124.hatenablog.com

検証したバージョンはfactory_bot 6.1.0です。

やりたいこと

以下のようなstrict loadingを使用したN+1を検知する設定 + strict laodingを無効化するためのメソッドを用意した実装を行っているとします。

class ApplicationRecord < ActiveRecord::Base
  self.strict_loading_by_default = true

  def strict_loading!(value = true)
    @strict_loading = value
  end
end

上記を行ったけどテストコードではstrict loadingを一時的に無効化したい場合にtraitを使ってシンプルにかけるようにしたいというのがやりたいことになります。

describe '#foo' do
  let(:foo) { create(:foo, :strict_loaded) }

  before do 
    create(:bar, foo: foo)
  end

  it { expect(foo.bars.length).to eq 1 }
end

各factoryで個別にtraitを書くのは手間なのでglobalに以下のようなtraitを定義したいものです。

  trait :strict_loaded do
    after(:build) { |record| record.strict_loading!(false) }
  end

globalに使えるtraitを定義する

globalに使えるtraitを定義する方法は簡単で以下のようにfactoryに紐付けずFactoryBot.define直下にtraitを置くことで定義できます。

FactoryBot.define do
  trait :strict_loaded do
    after(:build) { |record| record.strict_loading!(false) }
  end
end

全然知らなかったのですが、以下の通りテストコードでも検証されているので公式でサポートされている利用方法のようです👀✨

github.com

おわりに

FactoryBot便利ですね🤖✨

参考

stackoverflow.com