Rails 4搭配FactoryGirl时如何覆盖基础工厂的after(:build)方法
原因说明
FactoryGirl(适配Rails 4.2的4.x版本)的回调默认采用追加执行机制,不存在覆盖逻辑:同生命周期(如after(:build))的回调,不管定义在基础工厂、trait还是子工厂中,都会在对应节点按加载顺序全部触发,没有提供直接覆盖已有回调的配置项。
实现方法
两种方案均可实现需求,可根据现有代码结构选择:
方案1:拆分通用回调为独立trait(推荐)
不要把需要支持覆盖的回调直接写在基础工厂块内,将默认回调抽为独立trait,基础工厂默认引入该trait;自定义场景下直接使用自定义trait,不引入默认trait即可避免默认回调执行。
代码示例:
FactoryGirl.define do # 抽离默认after_build逻辑为独立trait trait :default_after_build do after(:build) do |user, vars| print "in main user after build.\n" def user.publish # 原有默认publish方法逻辑 end end end factory :user do # 基础工厂默认引入通用回调 default_after_build # 其余基础字段定义 # … trait :with_callbacks do # 此处不引入default_after_build,仅写自定义回调逻辑 after(:build) do |user, vars| print "after build my user\n" end # 其余自定义逻辑 # … end end end
调用效果:
- 执行
create(:user)时,自动加载默认trait,执行原有基础回调 - 执行
create(:user, :with_callbacks)时,仅加载自定义trait的回调,不会触发默认回调逻辑
方案2:回调内增加开关判断
如果不想调整现有trait结构,可以给基础回调增加跳过标记,需要覆盖时传入对应参数跳过基础逻辑即可。
代码示例:
FactoryGirl.define do factory :user do after(:build) do |user, vars| # 检测到跳过标记时直接终止基础回调执行 next if vars.skip_default_build_callback print "in main user after build.\n" def user.publish # 原有默认publish方法逻辑 end end # 其余基础字段定义 # … trait :with_callbacks do after(:build) do |user, vars| print "after build my user\n" end # 其余自定义逻辑 # … end end end
调用时传入跳过参数即可:
create(:user, :with_callbacks, skip_default_build_callback: true)
注意:FactoryGirl中trait回调的执行顺序早于基础工厂回调,传入的参数会先加载到evaluator中,基础回调内可以正常读取到标记值。
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

