タイトル読んでも「ちょっと何言ってるか分かんない」感じだが、要するにhas_one
やhas_many
で親子関係を持つモデルがあったとして、子のファクトリ生成時に親側の属性も設定するという話(その逆もしかり)。
例
たとえばUserクラスとConfigクラスがあったとして、それぞれ次のような関連を持ってるとする。
📄spec/factories/config.rb
class User < ApplicationRecord has_one :config end class Config < ApplicationRecord belongs_to :user end
各ユーザーが各々設定を持つというシチュエーションを想定している。で、この場合に親のファクトリをcreate(:config)
のような感じで作るときに、まとめてUser側の属性も設定したいということ。
通常の書き方だと、Configのインスタンスを得るにはこんな感じになるはず。(たぶん)
config = create(:user. name: '...', email: '...', config: build(:config, attr1: '...', attr2: '...')).config
それを次のように書けるようにする。
config = create(:config, attr1: '...', attr2: '...', user: { name: '...', email: '...' })
「なんだ、ほとんど変わんねえじゃねーか」とお思いになるかもしれない。しかし前者は、Configのインスタンスが欲しいんだということがひと目で分からない。また、build :config
してるのもいささか冗長だ。後者の方がテストの関心がConfigにあることが一目瞭然だし、タイプ量も少なくてすむ。細かいことだけど、こういうのって結構大事だと思うんだな。
ファクトリ定義
で、肝心のファクトリの定義だが、私はこんな感じに定義している。
FactoryGirl.define do factory :config do attr1 '...' attr2 '...' transient do user { {} } end after(:build) do |config, evaluator| config.user = build(:user, evaluator.user) if evaluator.user.present? end end end
user
をtransient
にしておきuserの属性(Hash)を渡してもらう。after(:build)
の中でuserのファクトリに横流してbuildしているのでuserのファクトリ定義を上書きすることができるというわけ。なお親から子の属性を設定する場合も同様の方法が使えると思う。
これがベストの解かは分からない。もっといい方法があれば教えて欲しいッス。
関連する記事
- Linuxで思い通りのキーマップを設定する【xkeysnail】
- Rails 4.1 + devise + omniauth-google-oauth2 で認証機能を実装する
- 自分はこんな感じでRailsアプリを作っております
- Railsアプリを『浅く』パフォーマンス・チューニングしてみる(その1)
- Ruby on Rails + Bootstrap3 + simple_form チュートリアル