I'm trying to use rails Faker gem to produce unique product names to make sample Item models in the database. I've used Faker multiple times but for some reason I can't produce new product names. I've made the nameMaker function to avoid possible early repeats, but I get a record invalidation just after one insert. Does anyone know how I could fix this?
seed.rb:
98.times do |n|
name = Item.nameMaker
description = Faker::Lorem.sentence(1)
price = Item.priceMaker
item = Item.create!(
name: name,
description: description,
price: price)
end
item.rb:
class Item < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 100 }
validates :description, presence: true,
length: { maximum: 1000 }
VALID_PRICE_REGEX = /\A\d+(?:\.\d{0,3})?\z/
validates :price, presence: true,
:format => { with: VALID_PRICE_REGEX },
:numericality => {:greater_than => 0}
validates_uniqueness_of :name
def Item.nameMaker
loop do
name = Item.newName
break if Item.find_by(name: name).nil?
end
return name
end
def Item.newName
Faker::Commerce.product_name
end
end
I figured it out after some experimentation, apparently the loop in some ways acts as like a function in terms of scoping. If you initialize a local variable in a loop, the function outside of the loop will not see it. In this case name
always returning the string Item
from the Item.nameMaker
function. Thus the first attempt would always succeed and the second one would obtain the validation restriction.
def Item.nameMaker
loop do
name = Faker::Commerce.product_name # 'Random Product Name'
puts "Name: #{name}" # "Name: Random Product Name"
item = Item.find_by(name: name)
if item.nil?
puts "#{name} not found" # "Random Product Name not found"
break
else
end
end
puts "Returning Name #{name}" # "Returning Name Item"
return name
end
I managed to fix this by initializing the local variable outside of the loop. By doing this the entire function now has visibility to the same local variable for some reason.
def Item.nameMaker
name = "" #initializing
loop do
name = Faker::Commerce.product_name # 'Random Product Name'
puts "Name: #{name}" # "Name: Random Product Name"
item = Item.find_by(name: name)
if item.nil?
puts "#{name} not found" # "Random Product Name not found"
break
else
end
end
puts "Returning Name #{name}" # "Returning Random Product Name"
return name
end