I'm using a sequence in Factory Girl to get unique values but I'm getting validation errors
Asked Answered
M

2

7

I have a model defined this way

class Lga < ActiveRecord::Base
  validates_uniqueness_of :code
  validates_presence_of :name
end 

I've defined a factory for Lgas with

Factory.sequence(:lga_id) { |n| n + 10000 }

Factory.define :lga do |l|
  id = Factory.next :lga_id
  l.code "lga_#{id}"
  l.name "LGA #{id}"
end

However, when I run

Factory.create(:lga)
Factory.create(:lga)

in script/console I get

>> Factory.create(:lga)
=> #<Lga id: 2, code: "lga_10001", name: "LGA 10001", created_at: "2010-03-18  23:55:29", updated_at: "2010-03-18 23:55:29">
>> Factory.create(:lga)
ActiveRecord::RecordInvalid: Validation failed: Code has already been taken
Mcdevitt answered 18/3, 2010 at 23:58 Comment(0)
M
7

The problem was that code and name attributes were not so called lazy attributes. I had thought of writing something like:

Factory.define :lga do |l|
  l.code { |n| "lga_#{n+10000}" }
end

but I wanted to reuse the id in the name attribute too. You can make sure than id is evaluated each time Factory.create is called by putting it in an after_build hook.

Factory.define :lga do |l|
   l.after_build do |lga|
     id = Factory.next :lga_id
     lga.code = "lga_#{id}"
     lga.name = "LGA #{id}"
   end
end

This only works in FactoryGirl 1.2.3 and above.

Mcdevitt answered 19/3, 2010 at 0:3 Comment(1)
I think you've left a debugger line in your last example code block ;)Longsome
H
2

The previous answer is still correct but in newer versions of FactoryGirl you will get a warning.

Factory.next has been depreciated. Use FactoryGirl.generate instead.

New Code should look like this:

Factory.define :lga do |l|
   l.after_build do |lga|
     id = FactoryGirl.generate :lga_id
     lga.code = "lga_#{id}"
     lga.name = "LGA #{id}"
   end
end

Source: http://notesofgreg.blogspot.co.uk/2012/07/foolproof-factorygirl-sequence.html

Hypoderm answered 10/7, 2012 at 13:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.