Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to refer to the object I'm Fabricating inside my Fabricator?

I'm using Ruby 2.1.1p76 and Rails 4.0.4 and the Fabrication gem.

Is it possible to refer to the object currently being fabricated?

I have a class Foo and a class Bar. I have fabricators for each. My problem is that each of class Foo and Bar contain a field that refers to the other class:

class Foo < ActiveRecord::Base
  has_many :bars
  belongs_to :current_bar, class_name: "Bar"
end

class Bar < ActiveRecord::Base
  belongs_to: :foo
end

It's bothersome to have to fabricate one, then the other and then set the reference for the first in my specs:

let!( :foo ) { Fabricate( :foo ) }
let!( :bar ) { Fabricate( :bar, foo: foo ) }

before( :each ) do
  foo.update( current_bar: bar )
end 

I'd much rather just fabricate a Foo and have its current_bar fabricated and already referring to the Foo I'm fabricating. I've read through the fabrication gem documentation and I can't find any way that this is possible. I may just be overlooking it. Does anyone know of a way to accomplish this?

For completeness -- fabricators:

Fabricator( :foo ) do
  current_bar nil
end

Fabricator( :bar ) do
  foo
end
like image 562
dm78 Avatar asked Apr 06 '14 17:04

dm78


People also ask

What is the fabrication meaning?

Fabrication is using processes to create component parts that can be used to make a product or structure, as well as the process of constructing an item from standardised parts. Manufacturing, meanwhile, is the processing of raw materials into a finished product that can be sold to a consumer.

What does fabricating the truth mean?

To call a statement a fabrication is to say it was made up, and is therefore a lie instead of being the truth. These days the word is more often used in this sense than with the earlier meaning.


1 Answers

Yup. overlooked it in the documentation.


You can define them in your Fabricators as a block that optionally receives the object being fabricated and a hash of any transient attributes defined. As with anything that works in the Fabricator, you can also define them when you call Fabricate and they will work just like you’d expect. The callbacks are also stackable, meaning that you can declare multiple of the same type in a fabricator and they will not be clobbered when you inherit another fabricator.

Fabricator(:place) do
  before_validation { |place, transients| place.geolocate! }
  after_create { |place, transients| Fabricate(:restaurant, place: place) }
end

Also, in my case, I needed to use the after_save callback. I was able set the current_bar on my foo object inside the fabricator, but once in the spec, the current_bar was still nil. The update method isn't available inside after_create (I'm new to ruby so I'm not sure why), but it is available inside after_save. Calling update got me going.

Fabricator(:foo) do

  transient :current_bar_data

  after_save { |foo, transients|
    bar = Fabricate( :bar, foo: foo, bar_data: transients[ :current_bar_data ] )
    foo.update( current_bar: bar )
  }

  current_bar nil
end

Now I can fabricate a foo complete with current_bar for my specs:

let!( :some_foo ) { Fabricate( :foo, current_bar_data: "some bar data" ) }
like image 121
dm78 Avatar answered Oct 13 '22 00:10

dm78