Search code examples
ruby-on-railsrubyforeign-keysseedingfaker

Seed database with foreign key - seeds.rb


I'm trying to seed database with Faker gem and I am succeeding when I am trying to seed just movies, but when I try to seed movies with each having 1-10 comments I'm getting bunch of different errors depends what I change.

Here is how my seeds.rb looks like:

require 'faker'

formats = %w[Beta VHS IMAX HD SuperHD 4K DVD BluRay]
genres = %w[Triller Comedy Horror Action Drama SciFi Documentary]
images = %w[magento.svg mysql.svg php.svg jquery.svg mongodb.svg prestashop.svg meteor.svg]

Movie.destroy_all
Comment.destroy_all

100.times do
  movie = Movie.create([{ name: Faker::Book.title,
                          director: Faker::Name.name,
                          description: Faker::FamilyGuy.quote,
                          year: rand(1920..2018),
                          length: rand(80..240),
                          format: formats[rand(formats.length)],
                          genre: genres[rand(genres.length)],
                          image: images[rand(images.length)],
                          thumbnail: images[rand(images.length)] }])
  unless movie.nil?
    rand(1..10).times do
      movie.comments.create(
        author: Faker::Name.name,
        title: Faker::Book.title,
        content: Faker::FamilyGuy.quote,
        rating: rand(1..5)
      )
    end
  end
  puts movie.inspect
end

Here is my comment model:

class Comment < ApplicationRecord
  belongs_to :movie
end

And here is my movie model:

class Movie < ApplicationRecord
  has_many :comments

  validates_presence_of :name, :director
#  validates_numericality_of :year, :length, greater_than: 0
  validates_uniqueness_of :name, message: 'Name is already used!'
#  validates_length_of :year, maximum: 4

  paginates_per 10

  def proper_name
    name.titleize
  end

end

Thanks for the help.


Solution

  • I can see two problems:

    1. In Movie.create, you need to remove the square brackets. That's because the ActiveRecord create method needs a Hash, not an Array. While you're at it, you can remove the curly braces as well, and your arguments will still be recognized as a Hash.

    2. Checking to see if movie is nil is not the right test, as movie will always exist, even if it wasn't saved to the database. Change your test from unless movie.nil? to if movie.persisted? This will avoid an error caused by trying to save comments to a movie that isn't saved to the database.

    So your code should look like this:

    100.times do
      movie = Movie.create(name: Faker::Book.title,
                           director: Faker::Name.name,
                           description: Faker::FamilyGuy.quote,
                           year: rand(1920..2018),
                           length: rand(80..240),
                           format: formats[rand(formats.length)],
                           genre: genres[rand(genres.length)],
                           image: images[rand(images.length)],
                           thumbnail: images[rand(images.length)])
      if movie.persisted?
        rand(1..10).times do
          movie.comments.create(
              author: Faker::Name.name,
              title: Faker::Book.title,
              content: Faker::FamilyGuy.quote,
              rating: rand(1..5)
          )
        end
      end
      puts movie.inspect
    end
    

    Why weren't some movies being saved? I suspect you were running out of movie titles and then failing your uniqueness constraint. Faker has a finite number of responses for any category. I think there are only 22 unique Faker::Book.title responses.