3

I have a FactoryGirl for a model class. In this model, I defined some traits. In some traits, I don't want FactoryGirl callback calling but I don't know how. For example here is my code:

FactoryGirl.define do
  factory :product do
    sequence(:promotion_item_code) { |n| "promotion_item_code#{n}" }

    after :create do |product|
      FactoryGirl.create_list :product_details, 1, :product => product
    end

    trait :special_product do
       # do some thing
       # and don't want to run FactoryGirl callback
    end
end

In this code, I don't want :special_product trait calls after :create. I don't know how to do this.

@Edit: the reason I want to this because sometimes I want generate data from parent -> children. But sometimes I want vice versa generate from children to parent. So When I go from children -> parent, callback at parent is called so children is created twice. That is not what I want.

@Edit 2: My question is prevent callback from FactoryGirl, not from ActiveRecord model.

Thanks

Trần Kim Dự
  • 5,872
  • 12
  • 55
  • 107
  • Possible duplicate of [Skip callbacks on Factory Girl and Rspec](http://stackoverflow.com/questions/8751175/skip-callbacks-on-factory-girl-and-rspec) – Wes Foster Mar 09 '17 at 13:28
  • 1
    @WesFoster Nope. Please read carefully answer and question first. Your post is about skip ActiveRecord callbacks. – Trần Kim Dự Mar 09 '17 at 13:32

2 Answers2

3

You can use transient attributes to achieve that.

Like:

factory :product do
  transient do
    create_products true
  end

  sequence(:promotion_item_code) { |n| "promotion_item_code#{n}" }

  after :create do |product, evaluator|
    FactoryGirl.create_list(:product_details, 1, :product => product) if evaluator.create_products
  end

  trait :special_product do
     # do some thing
     # and don't want to run FactoryGirl callback
  end
end

But I think that a better way to model this problem is to define a trait for the "base case" or to have multiple factories.

Fredius
  • 175
  • 1
  • 4
  • No. The problem still the same because `create_products` always set. – Trần Kim Dự Mar 09 '17 at 15:56
  • When you don't want to create the products you should pass the `create_products` in false. – Fredius Mar 09 '17 at 15:58
  • I'm using association. I don't know the way for passing data. Here is my code: `association :product, :factory => [:product, :special_product]` thanks – Trần Kim Dự Mar 09 '17 at 16:32
  • 1
    I think that `association :product, factory: [:product, :special_product], create_products: false` should work. For more information: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#traits – Fredius Mar 09 '17 at 17:15
  • thanks so much. it works :D although I cannot mapping your link (about trait) with your code (use association + trait + custom attributes like transient) :D can you tell me more about this, where can you get this from document. thanks :D – Trần Kim Dự Mar 09 '17 at 17:27
  • It isn't the exact same example, but if you search for `association` you should see that it passes attributes to the association like `name: "John Doe"` with the `trait` as well – Fredius Mar 09 '17 at 17:32
0

You could use the same approach as described in the Factory Girl docs for a has_many relationship:

factory :product_detail do
  product
  #... other product_detail attributes
end

factory :product do
  sequence(:promotion_item_code) { |n| "promotion_item_code#{n}" }

  factory :product_with_details do
    transient do
      details_count 1  # to match your example.
    end

    after(:create) do |product, evaluator|
      create_list(:product_detail, evaluator.details_count, product: product)
    end
  end

  trait :special_product do
    # do some thing
    # and don't want to run FactoryGirl callback
  end
end

This allows you to generate data for the parent->children:

create(:product_with_details)                   # creates a product with one detail.
create(:product_with_details, details_count: 5) # if you want more than 1 detail.

...and for the special product just

# does not create any product_details.
create(:product)
create(:product, :special_product)

To generate for children->parent

create(:product_detail)
s3tjan
  • 1,118
  • 10
  • 13