paulelliott / fabrication

This project has moved to GitLab! Please check there for the latest updates.
https://gitlab.com/fabrication-gem/fabrication
MIT License
998 stars 97 forks source link

fabricate failing to build interit values for nested associations through nested attributes #293

Closed ajays1991 closed 7 years ago

ajays1991 commented 7 years ago

Hi,

I observed a weird behaviour with fabrication.

Followings are my models


# frozen_string_literal: true

class Lead < ApplicationRecord
  accept_nested_attributes_for :followers
  has_many :followings, dependent: :destroy
  has_many :followers, as: :followable, through: :followings, source: :followable, source_type: 'Lead'
end

class Pipeline < ApplicationRecord
  accept_nested_attributes_for :followers
  has_many :followings, dependent: :destroy
  has_many :followers, as: :followable, through: :followings, source: :followable, source_type: 'Lead'
end

class Followings < ApplicationRecord
  inherits_from :followable, attr: :account_id
  belongs_to :followable, polymorphic: true
end

Model Fabricators


# frozen_string_literal: true

Fabricator(:lead) do
  max_budget   { Faker::Number.number(8) }
  min_budget   { Faker::Number.number(5) }
  requirements { Faker::ChuckNorris.fact }
end

# frozen_string_literal: true

Fabricator(:following) do
  user    nil
end

When i try to fabricate lead with followers, this fails


 @lead =
        @account.fabricate(
          :lead,
          pipeline: @pipeline,
          target: @account.fabricate(:contact),
          status: @status_old,
          assignee: @user,
          followers: [@account.owner]
        )

with the following error. ActiveRecord::RecordInvalid: Validation failed: Followings is invalid

as it now getting the account_id from parent(inherits_from). I debug it and also found that followable_id is also nil. whereas the same is working fine through controllers and model create attributes.


lead = account.leads.create({
    target_attributes: {
    name:'ajay', email:'dsads.com'
    }, 
    target_type: 'Contact',
    pipeline: pipeline,
    follower_ids: [account.owner.id]
    })

This points me different execution behaviour for models through fabricator or normal.

Thanks

paulelliott commented 7 years ago

You are correct that the execution behavior is different. Fabrication is not creating everything using nested attributes as your code does through a controller. You have validations on the associations and the way you're invoking fabrication is causing objects to persist in an order your application code does not expect.

Your controller logic is likely doing a build on each object while it creates the graph of objects to save then when you call save on the parent it persists the group all at once. You should play around with using fabricate.build on the child objects and I think you'll see better results.