Search code examples
ruby-on-railsruby-on-rails-4randomfaker

Rails faker gem produces same product name


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

Solution

  • 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