Closed gamov closed 10 years ago
What you're looking for are transient attributes.
Best of luck!
I'm aware of the transient attributes, however, in my case, I don't want the user of the factory to have to remember to use the transient attribute. My real case is of course more complicated than this one. Basically, I have a quantity dependency that I need to handle if user set a quantity attribute (by setting the association quantity > quantity).
No 'evaluator' I could tap in the block?
@gamov can you provide the real example? I'm not sure changing quantity like that is actually ideal because it introduces a level of indirection (if you set a value, I'd assume that value be the value assigned and not change).
First of all, thanks for your help. I switched around the requirement and it leads to cleaner factories and only broke a few tests which were easily fixed. Now quantity of the nested association is always valid.
class ShippingItem < ActiveRecord::Base
belongs_to :purchased_item
validate { errors.add(:quantity, "cannot be higher than available quantity: #{purchased_item.quantity}") if purchased_item.quantity < quantity }
end
Shipping Item factory:
factory :shipping_item do
quantity { rand 3..100 }
purchased_item {association :purchased_item, quantity: (quantity..(quantity + 100)).to_a.sample}
end
This works fine if you set the quantity or not when invoking the shipping item factory (which was my original question). Let say now that I want to set the delivery site for the purchased item from the shipping item factory. I would do:
factory :shipping_item do
quantity { rand 3..100 }
ignore {delivery_site nil}
purchased_item {association :purchased_item,
quantity: (quantity..(quantity + 100)).to_a.sample,
delivery_site: (delivery_site || FactoryGirl.build :delivery_site)
}
end
However, I can see it becoming a pattern and doesn't feel 'right' or DRY. Is it the usual way?
@gamov okay, this is starting to make more sense now, and yes, I agree this isn't DRY.
In cases like this (especially because this is likely a simple case and there are MUCH more complicated ones out there), I actually create support classes for building complicated data (either because there's a LOT of associated data or certain aspects change and it impacts creation of other factories, like this). The example I point to in cases like this is here: https://github.com/thoughtbot/factory_girl/issues/230#issuecomment-22414812
At the end of the day, factory_girl can't (and won't!) handle every permutation of every way objects get associated and built. It's just not possible. In cases like yours where there's little things that change, I always recommend solving things with pure Ruby. It's flexible, extensible, and technically testable if you want.
Hopefully this helps - I know "factory_girl can't handle this well" doesn't sound ideal, but it really is, since it keeps factory_girl's interface clean and understandable and removes the chance for odd edge cases.
I still wish we could access the constructor supplied hash to check what has been supplied to make some choice in the lazy attribute block…
I tried asking this twice in the Google Group but both time my post disappeared…:
I would like to do different things if a certain attribute is passed to the constructor or not (using default), e.g.:
so the quantity will have different value if I specify the quantity or not in the constructor:
Is this possible?
PS: In the getting started document, I think it would be good to specify that association attributes are processed before other attributes even though they could be defined after them in the define block.