I’m upgrade a codebase from 1.8 to 1.9. I’m encountering a couple places in my code (only specs, not sure if that’s a coincidence) where there are problems with blocks that don’t have a variable. Giving them a dummy variable fixes the problem. Here’s an example:
In a factory girl factory, this works under 1.8:
Factory.define :thing do |t|
t.price { 1 - 0.01*rand(10) }
end
Under 1.9, rand(10) returns nil. Very odd. I was racking my brain for why the environment would be different inside the block. The thing is, rand isn’t even from the standard library — it’s from the core language! So there isn’t really a way that the environment would make a difference.
Then I remembered that some other places in my specs were breaking because of no-variable blocks, so on a whim I threw one in there, and lo and behold it worked.
Factory.define :thing do |t|
t.price { |dummy| 1 - 0.01*rand(10) }
end
What is going on here?
In recent versions of factory_girl, defining an attribute without a block argument uses instance_eval, and it assumes that bare method calls are looking for previous attribute definitions, methods on your model, or syntax methods like “create” or “build.”
In order to make attributes like “open” or “file” work correctly, the proxy object undefines most private methods including “rand.” This means that you need to use “Kernel.rand” instead of just “rand.”
You can see the relevant source here: https://github.com/thoughtbot/factory_girl/blob/master/lib/factory_girl/evaluator.rb#L16