Reputation: 2267
I'm trying to build factories for relatively complex models.
I have a Pressroom model, which belongs to Source, and Source has many Pressrooms. When creating the Source, if pressrooms is empty, an initial pressroom is created in an after_create filter. The pressroom site must be unique per source.
class Source
has_many :pressrooms
after_create :create_initial_pressroom! # if pressrooms.empty?
...
end
class Pressroom
belongs_to :source
# source.pressrooms.map(&:site) should have unique elements
validate_on_create :check_unique_site
end
This leads to my problem: My Pressroom.make
fails, because it builds a Source, which has no pressrooms, so the after_create
callback creates one, and when the Pressroom.make
tries to finish up, its site is not unique. I don't want to create two pressrooms when I run Pressroom.make
My attempt to solve this is to make the source association in the pressroom blueprint reference the pressroom. Sort of what Source.create :pressrooms => [Pressroom.new]
would do.
Pressroom.blueprint do
source { Source.make :pressrooms => [self] }
site { source.site }
end
Unfortunatly, self
is not yet a Pressroom. It's an instance of Machinist::Lathe, so I get an ActiveRecord::AssociationTypeMismatch exception.
I'm a bit of a newbie when it comes to factories and Machinist. I don't want to have to change the business logic, and I want to be able to cleanly make pressrooms with Pressroom.make
without making two pressrooms in the process. If switching to factory-girl would help, I'm open to that.
I'd be grateful for any ideas on how to solve this.
Upvotes: 4
Views: 1655
Reputation: 2267
Googling around, I found some hints on http://webcrisps.wordpress.com/2009/08/13/stubbing-before_create-callbacks-in-a-machinist-blueprint/ – to stub the after_create :create_initial_pressroom!
callback on Source, in the Source blueprint – using Machinist 2 and Mocha here:
Pressroom.blueprint do
source { Source.make!(:without_initial_pressroom) }
site { object.source.site }
end
Source.blueprint do
site
end
Source.blueprint(:without_initial_pressroom) do
object.stubs(:create_initial_pressroom!).returns(true)
end
This way, Pressroom.make!
works like it should, Source.make!
works like it should, and... I guess I'm happy. But still a bit perplexed by the problems I ran into in the solution I tried above (both in machinist 1 and 2).
If anyone knows how to make this work with object
, let me know. It'd be a lot cleaner, and besides, I generally don't like accepting my own answers here on stackoverflow.
Upvotes: 2
Reputation: 32067
Are you using Machinist 1 or 2? These suggestions for Machinist 2 and may or may not work in Machinist 1. I can't remember how you do this in Machinist 1 (and can't be bothered to google!).
To do it in the way you're suggesting, you need to use object
:
Pressroom.blueprint do
source { Source.make :pressrooms => [object] }
site { source.site }
end
But a much nicer way to do it is to take advantage of the fact Machinst knows about the models associations and just let it do its thing:
Pressroom.blueprint do
source
site { source.site }
end
Assuming your associations are setup correctly, that should work. See the Blueprints wiki page for more.
Upvotes: 1