From c3f3575dcf360b8bedaffc84abd1e5324385a181 Mon Sep 17 00:00:00 2001 From: Michael Kohl Date: Fri, 29 May 2020 21:21:00 +0700 Subject: [PATCH] Make DB seeding idempotent (#8153) --- db/seeds.rb | 756 ++++++++++++++++++++++++++-------------------------- 1 file changed, 381 insertions(+), 375 deletions(-) diff --git a/db/seeds.rb b/db/seeds.rb index 5b727e155..26b893a65 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,128 +1,146 @@ +# rubocop:disable Rails/Output + +# NOTE: when adding new data, please use this class to ensure the seed tasks +# stays idempotent. +class Seeder + def initialize + @counter = 0 + end + + def create_if_none(klass, count = nil) + @counter += 1 + plural = klass.name.pluralize + + if klass.none? + message = ["Creating", count, plural].compact.join(" ") + puts " #{@counter}. #{message}." + yield + else + puts " #{@counter}. #{plural} already exist. Skipping." + end + end +end + # we use this to be able to increase the size of the seeded DB at will # eg.: `SEEDS_MULTIPLIER=2 rails db:seed` would double the amount of data +seeder = Seeder.new SEEDS_MULTIPLIER = [1, ENV["SEEDS_MULTIPLIER"].to_i].max -counter = 0 -Rails.logger.info "Seeding with multiplication factor: #{SEEDS_MULTIPLIER}" +puts "Seeding with multiplication factor: #{SEEDS_MULTIPLIER}\n\n" ############################################################################## -counter += 1 -Rails.logger.info "#{counter}. Creating Organizations" - -3.times do - Organization.create!( - name: Faker::TvShows::SiliconValley.company, - summary: Faker::Company.bs, - remote_profile_image_url: logo = Faker::Company.logo, - nav_image: logo, - url: Faker::Internet.url, - slug: "org#{rand(10_000)}", - github_username: "org#{rand(10_000)}", - twitter_username: "org#{rand(10_000)}", - bg_color_hex: Faker::Color.hex_color, - text_color_hex: Faker::Color.hex_color, - ) +seeder.create_if_none(Organization) do + 3.times do + Organization.create!( + name: Faker::TvShows::SiliconValley.company, + summary: Faker::Company.bs, + remote_profile_image_url: logo = Faker::Company.logo, + nav_image: logo, + url: Faker::Internet.url, + slug: "org#{rand(10_000)}", + github_username: "org#{rand(10_000)}", + twitter_username: "org#{rand(10_000)}", + bg_color_hex: Faker::Color.hex_color, + text_color_hex: Faker::Color.hex_color, + ) + end end ############################################################################## num_users = 10 * SEEDS_MULTIPLIER -counter += 1 -Rails.logger.info "#{counter}. Creating #{num_users} Users" +users_in_random_order = seeder.create_if_none(User, num_users) do + roles = %i[trusted chatroom_beta_tester workshop_pass] -roles = %i[trusted chatroom_beta_tester workshop_pass] + num_users.times do |i| + name = Faker::Name.unique.name -num_users.times do |i| - name = Faker::Name.unique.name + user = User.create!( + name: name, + summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false), + profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")), + website_url: Faker::Internet.url, + twitter_username: Faker::Internet.username(specifier: name), + email_comment_notifications: false, + email_follower_notifications: false, + email: Faker::Internet.email(name: name, separators: "+", domain: Faker::Internet.domain_word.first(20)), # Emails limited to 50 characters + confirmed_at: Time.current, + password: "password", + ) - user = User.create!( - name: name, - summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false), - profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")), - website_url: Faker::Internet.url, - twitter_username: Faker::Internet.username(specifier: name), - email_comment_notifications: false, - email_follower_notifications: false, - email: Faker::Internet.email(name: name, separators: "+", domain: Faker::Internet.domain_word.first(20)), # Emails limited to 50 characters - confirmed_at: Time.current, - password: "password", - ) + if i.zero? + user.add_role(:trusted) # guarantee at least one moderator + else + user.add_role(roles[rand(0..roles.length)]) # includes chance of having no role + end - if i.zero? - user.add_role(:trusted) # guarantee at least one moderator - else - user.add_role(roles[rand(0..roles.length)]) # includes chance of having no role - end - - Identity.create!( - provider: "twitter", - uid: i.to_s, - token: i.to_s, - secret: i.to_s, - user: user, - auth_data_dump: { - "extra" => { - "raw_info" => { "lang" => "en" } + Identity.create!( + provider: "twitter", + uid: i.to_s, + token: i.to_s, + secret: i.to_s, + user: user, + auth_data_dump: { + "extra" => { + "raw_info" => { "lang" => "en" } + }, + "info" => { "nickname" => user.username } }, - "info" => { "nickname" => user.username } - }, - ) -end - -Organization.find_each do |organization| - admins = [] - admin_id = User.where.not(id: admins).order(Arel.sql("RANDOM()")).first.id - - OrganizationMembership.create!( - user_id: admin_id, - organization_id: organization.id, - type_of_user: "admin", - ) - - admins << admin_id - - 2.times do - OrganizationMembership.create!( - user_id: User.where.not(id: OrganizationMembership.pluck(:user_id)).order(Arel.sql("RANDOM()")).first.id, - organization_id: organization.id, - type_of_user: "member", ) end -end -users_in_random_order = User.order(Arel.sql("RANDOM()")) + Organization.find_each do |organization| + admins = [] + admin_id = User.where.not(id: admins).order(Arel.sql("RANDOM()")).first.id + + OrganizationMembership.create!( + user_id: admin_id, + organization_id: organization.id, + type_of_user: "admin", + ) + + admins << admin_id + + 2.times do + OrganizationMembership.create!( + user_id: User.where.not(id: OrganizationMembership.pluck(:user_id)).order(Arel.sql("RANDOM()")).first.id, + organization_id: organization.id, + type_of_user: "member", + ) + end + + User.order(Arel.sql("RANDOM()")) + end +end ############################################################################## -counter += 1 -Rails.logger.info "#{counter}. Creating Tags" - -tags = %w[beginners career computerscience git go +seeder.create_if_none(Tag) do + tags = %w[beginners career computerscience git go java javascript linux productivity python security webdev] -tags.each do |tag_name| - Tag.create!( - name: tag_name, - bg_color_hex: Faker::Color.hex_color, - text_color_hex: Faker::Color.hex_color, - supported: true, - ) + tags.each do |tag_name| + Tag.create!( + name: tag_name, + bg_color_hex: Faker::Color.hex_color, + text_color_hex: Faker::Color.hex_color, + supported: true, + ) + end end ############################################################################## num_articles = 25 * SEEDS_MULTIPLIER -counter += 1 -Rails.logger.info "#{counter}. Creating #{num_articles} Articles" +seeder.create_if_none(Article, num_articles) do + num_articles.times do |i| + tags = [] + tags << "discuss" if (i % 3).zero? + tags.concat Tag.order(Arel.sql("RANDOM()")).limit(3).pluck(:name) -num_articles.times do |i| - tags = [] - tags << "discuss" if (i % 3).zero? - tags.concat Tag.order(Arel.sql("RANDOM()")).limit(3).pluck(:name) - - markdown = <<~MARKDOWN + markdown = <<~MARKDOWN --- title: #{Faker::Book.title} #{Faker::Lorem.sentence(word_count: 2).chomp('.')} published: true @@ -133,131 +151,127 @@ num_articles.times do |i| #{Faker::Hipster.paragraph(sentence_count: 2)} #{Faker::Markdown.random} #{Faker::Hipster.paragraph(sentence_count: 2)} - MARKDOWN + MARKDOWN - Article.create!( - body_markdown: markdown, - featured: true, - show_comments: true, - user_id: User.order(Arel.sql("RANDOM()")).first.id, - ) + Article.create!( + body_markdown: markdown, + featured: true, + show_comments: true, + user_id: User.order(Arel.sql("RANDOM()")).first.id, + ) + end end ############################################################################## num_comments = 30 * SEEDS_MULTIPLIER -counter += 1 -Rails.logger.info "#{counter}. Creating #{num_comments} Comments" +seeder.create_if_none(Comment, num_comments) do + num_comments.times do + attributes = { + body_markdown: Faker::Hipster.paragraph(sentence_count: 1), + user_id: User.order(Arel.sql("RANDOM()")).first.id, + commentable_id: Article.order(Arel.sql("RANDOM()")).first.id, + commentable_type: "Article" + } -num_comments.times do - attributes = { - body_markdown: Faker::Hipster.paragraph(sentence_count: 1), - user_id: User.order(Arel.sql("RANDOM()")).first.id, - commentable_id: Article.order(Arel.sql("RANDOM()")).first.id, - commentable_type: "Article" + Comment.create!(attributes) + end +end + +############################################################################## + +seeder.create_if_none(Podcast) do + image_file = Rails.root.join("spec/support/fixtures/images/image1.jpeg") + + podcast_objects = [ + { + title: "CodeNewbie", + description: "", + feed_url: "http://feeds.codenewbie.org/cnpodcast.xml", + itunes_url: "https://itunes.apple.com/us/podcast/codenewbie/id919219256", + slug: "codenewbie", + twitter_username: "CodeNewbies", + website_url: "https://www.codenewbie.org/podcast", + main_color_hex: "2faa4a", + overcast_url: "https://overcast.fm/itunes919219256/codenewbie", + android_url: "https://subscribeonandroid.com/feeds.podtrac.com/q8s8ba9YtM6r", + image: Rack::Test::UploadedFile.new(image_file, "image/jpeg"), + published: true + }, + { + title: "CodingBlocks", + description: "", + feed_url: "http://feeds.podtrac.com/c8yBGHRafqhz", + slug: "codingblocks", + twitter_username: "CodingBlocks", + website_url: "http://codingblocks.net", + main_color_hex: "111111", + overcast_url: "https://overcast.fm/itunes769189585/coding-blocks", + android_url: "http://subscribeonandroid.com/feeds.podtrac.com/c8yBGHRafqhz", + image: Rack::Test::UploadedFile.new(image_file, "image/jpeg"), + published: true + }, + { + title: "Talk Python", + description: "", + feed_url: "https://talkpython.fm/episodes/rss", + slug: "talkpython", + twitter_username: "TalkPython", + website_url: "https://talkpython.fm", + main_color_hex: "181a1c", + overcast_url: "https://overcast.fm/itunes979020229/talk-python-to-me", + android_url: "https://subscribeonandroid.com/talkpython.fm/episodes/rss", + image: Rack::Test::UploadedFile.new(image_file, "image/jpeg"), + published: true + }, + { + title: "Developer on Fire", + description: "", + feed_url: "http://developeronfire.com/rss.xml", + itunes_url: "https://itunes.apple.com/us/podcast/developer-on-fire/id1006105326", + slug: "developeronfire", + twitter_username: "raelyard", + website_url: "http://developeronfire.com", + main_color_hex: "343d46", + overcast_url: "https://overcast.fm/itunes1006105326/developer-on-fire", + android_url: "http://subscribeonandroid.com/developeronfire.com/rss.xml", + image: Rack::Test::UploadedFile.new(image_file, "image/jpeg"), + published: true + }, + ] + + podcast_objects.each do |attributes| + podcast = Podcast.create!(attributes) + Podcasts::GetEpisodesWorker.perform_async(podcast_id: podcast.id) + end +end +############################################################################## + +seeder.create_if_none(Broadcast) do + broadcast_messages = { + set_up_profile: "Welcome to DEV! 👋 I'm Sloan, the community mascot and I'm here to help get you started. Let's begin by setting up your profile!", + welcome_thread: "Sloan here again! 👋 DEV is a friendly community. Why not introduce yourself by leaving a comment in the welcome thread!", + twitter_connect: "You're on a roll! 🎉 Do you have a Twitter account? Consider connecting it so we can @mention you if we share your post via our Twitter account @thePracticalDev.", + github_connect: "You're on a roll! 🎉 Do you have a GitHub account? Consider connecting it so you can pin any of your repos to your profile.", + customize_feed: "Hi, it's me again! 👋 Now that you're a part of the DEV community, let's focus on personalizing your content. You can start by following some tags to help customize your feed! 🎉", + customize_experience: "Sloan here! 👋 Did you know that that you can customize your DEV experience? Try changing your font and theme and find the best style for you!", + start_discussion: "Sloan here! 👋 I noticed that you haven't started a discussion yet. Starting a discussion is easy to do; just click on 'Write a Post' in the sidebar of the tag page to get started!", + ask_question: "Sloan here! 👋 I noticed that you haven't asked a question yet. Asking a question is easy to do; just click on 'Write a Post' in the sidebar of the tag page to get started!", + discuss_and_ask: "Sloan here! 👋 I noticed that you haven't asked a question or started a discussion yet. It's easy to do both of these; just click on 'Write a Post' in the sidebar of the tag page to get started!", + download_app: "Sloan here, with one last tip! 👋 Have you downloaded the DEV mobile app yet? Consider downloading it so you can access all of your favorite DEV content on the go!" } - Comment.create!(attributes) -end + broadcast_messages.each do |type, message| + Broadcast.create!( + title: "Welcome Notification: #{type}", + processed_html: message, + type_of: "Welcome", + active: true, + ) + end -############################################################################## - -counter += 1 -Rails.logger.info "#{counter}. Creating Podcasts" - -image_file = Rails.root.join("spec/support/fixtures/images/image1.jpeg") - -podcast_objects = [ - { - title: "CodeNewbie", - description: "", - feed_url: "http://feeds.codenewbie.org/cnpodcast.xml", - itunes_url: "https://itunes.apple.com/us/podcast/codenewbie/id919219256", - slug: "codenewbie", - twitter_username: "CodeNewbies", - website_url: "https://www.codenewbie.org/podcast", - main_color_hex: "2faa4a", - overcast_url: "https://overcast.fm/itunes919219256/codenewbie", - android_url: "https://subscribeonandroid.com/feeds.podtrac.com/q8s8ba9YtM6r", - image: Rack::Test::UploadedFile.new(image_file, "image/jpeg"), - published: true - }, - { - title: "CodingBlocks", - description: "", - feed_url: "http://feeds.podtrac.com/c8yBGHRafqhz", - slug: "codingblocks", - twitter_username: "CodingBlocks", - website_url: "http://codingblocks.net", - main_color_hex: "111111", - overcast_url: "https://overcast.fm/itunes769189585/coding-blocks", - android_url: "http://subscribeonandroid.com/feeds.podtrac.com/c8yBGHRafqhz", - image: Rack::Test::UploadedFile.new(image_file, "image/jpeg"), - published: true - }, - { - title: "Talk Python", - description: "", - feed_url: "https://talkpython.fm/episodes/rss", - slug: "talkpython", - twitter_username: "TalkPython", - website_url: "https://talkpython.fm", - main_color_hex: "181a1c", - overcast_url: "https://overcast.fm/itunes979020229/talk-python-to-me", - android_url: "https://subscribeonandroid.com/talkpython.fm/episodes/rss", - image: Rack::Test::UploadedFile.new(image_file, "image/jpeg"), - published: true - }, - { - title: "Developer on Fire", - description: "", - feed_url: "http://developeronfire.com/rss.xml", - itunes_url: "https://itunes.apple.com/us/podcast/developer-on-fire/id1006105326", - slug: "developeronfire", - twitter_username: "raelyard", - website_url: "http://developeronfire.com", - main_color_hex: "343d46", - overcast_url: "https://overcast.fm/itunes1006105326/developer-on-fire", - android_url: "http://subscribeonandroid.com/developeronfire.com/rss.xml", - image: Rack::Test::UploadedFile.new(image_file, "image/jpeg"), - published: true - }, -] - -podcast_objects.each do |attributes| - podcast = Podcast.create!(attributes) - Podcasts::GetEpisodesWorker.perform_async(podcast_id: podcast.id) -end - -############################################################################## - -counter += 1 -Rails.logger.info "#{counter}. Creating Broadcasts and Welcome Thread" - -broadcast_messages = { - set_up_profile: "Welcome to DEV! 👋 I'm Sloan, the community mascot and I'm here to help get you started. Let's begin by setting up your profile!", - welcome_thread: "Sloan here again! 👋 DEV is a friendly community. Why not introduce yourself by leaving a comment in the welcome thread!", - twitter_connect: "You're on a roll! 🎉 Do you have a Twitter account? Consider connecting it so we can @mention you if we share your post via our Twitter account @thePracticalDev.", - github_connect: "You're on a roll! 🎉 Do you have a GitHub account? Consider connecting it so you can pin any of your repos to your profile.", - customize_feed: "Hi, it's me again! 👋 Now that you're a part of the DEV community, let's focus on personalizing your content. You can start by following some tags to help customize your feed! 🎉", - customize_experience: "Sloan here! 👋 Did you know that that you can customize your DEV experience? Try changing your font and theme and find the best style for you!", - start_discussion: "Sloan here! 👋 I noticed that you haven't started a discussion yet. Starting a discussion is easy to do; just click on 'Write a Post' in the sidebar of the tag page to get started!", - ask_question: "Sloan here! 👋 I noticed that you haven't asked a question yet. Asking a question is easy to do; just click on 'Write a Post' in the sidebar of the tag page to get started!", - discuss_and_ask: "Sloan here! 👋 I noticed that you haven't asked a question or started a discussion yet. It's easy to do both of these; just click on 'Write a Post' in the sidebar of the tag page to get started!", - download_app: "Sloan here, with one last tip! 👋 Have you downloaded the DEV mobile app yet? Consider downloading it so you can access all of your favorite DEV content on the go!" -} - -broadcast_messages.each do |type, message| - Broadcast.create!( - title: "Welcome Notification: #{type}", - processed_html: message, - type_of: "Welcome", - active: true, - ) -end - -welcome_thread_content = <<~HEREDOC + welcome_thread_content = <<~HEREDOC --- title: Welcome Thread - v0 published: true @@ -268,204 +282,196 @@ welcome_thread_content = <<~HEREDOC Hey there! Welcome to #{ApplicationConfig['COMMUNITY_NAME']}! Leave a comment below to introduce yourself to the community!✌️ -HEREDOC + HEREDOC -Article.create!( - body_markdown: welcome_thread_content, - user: User.dev_account, -) - -############################################################################## - -counter += 1 -Rails.logger.info "#{counter}. Creating Chat Channels and Messages" - -%w[Workshop Meta General].each do |chan| - ChatChannel.create!( - channel_name: chan, - channel_type: "open", - slug: chan, - ) -end - -direct_channel = ChatChannel.create_with_users(users: User.last(2), channel_type: "direct") -Message.create!( - chat_channel: direct_channel, - user: User.last, - message_markdown: "This is **awesome**", -) - -############################################################################## - -counter += 1 -Rails.logger.info "#{counter}. Creating HTML Variants" - -HtmlVariant.create!( - name: rand(100).to_s, - group: "badge_landing_page", - html: rand(1000).to_s, - success_rate: 0, - published: true, - approved: true, - user_id: User.first.id, -) - -############################################################################## - -counter += 1 -Rails.logger.info "#{counter}. Creating Badges" - -5.times do - Badge.create!( - title: "#{Faker::Lorem.word} #{rand(100)}", - description: Faker::Lorem.sentence, - badge_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")), - ) -end - -users_in_random_order.limit(10).each do |user| - user.badge_achievements.create!( - badge: Badge.order(Arel.sql("RANDOM()")).limit(1).take, - rewarding_context_message_markdown: Faker::Markdown.random, + Article.create!( + body_markdown: welcome_thread_content, + user: User.dev_account, ) end ############################################################################## -counter += 1 -Rails.logger.info "#{counter}. Creating FeedbackMessages" +seeder.create_if_none(ChatChannel) do + %w[Workshop Meta General].each do |chan| + ChatChannel.create!( + channel_name: chan, + channel_type: "open", + slug: chan, + ) + end -mod = User.first - -FeedbackMessage.create!( - reporter: User.last, - feedback_type: "spam", - message: Faker::Lorem.sentence, - category: "spam", - status: "Open", -) - -FeedbackMessage.create!( - reporter: mod, - feedback_type: "abuse-reports", - message: Faker::Lorem.sentence, - reported_url: "example.com", - category: "harassment", - status: "Open", -) - -Reaction.create!( - category: "vomit", - reactable_id: User.last.id, - reactable_type: "User", - user_id: mod.id, -) - -3.times do - Reaction.create!( - category: "vomit", - reactable_id: Article.order(Arel.sql("RANDOM()")).first.id, - reactable_type: "Article", - user_id: mod.id, + direct_channel = ChatChannel.create_with_users(users: User.last(2), channel_type: "direct") + Message.create!( + chat_channel: direct_channel, + user: User.last, + message_markdown: "This is **awesome**", ) end ############################################################################## -counter += 1 -Rails.logger.info "#{counter}. Creating Listing Categories" - -CATEGORIES = [ - { - slug: "cfp", - cost: 1, - name: "Conference CFP", - rules: "Currently open for proposals, with link to form." - }, - { - slug: "education", - cost: 1, - name: "Education/Courses", - rules: "Educational material and/or schools/bootcamps." - }, - { - slug: "jobs", - cost: 25, - name: "Job Listings", - rules: "Companies offering employment right now." - }, - { - slug: "forsale", - cost: 1, - name: "Stuff for Sale", - rules: "Personally owned physical items for sale." - }, - { - slug: "events", - cost: 1, - name: "Upcoming Events", - rules: "In-person or online events with date included." - }, - { - slug: "misc", - cost: 1, - name: "Miscellaneous", - rules: "Must not fit in any other category." - }, -].freeze - -CATEGORIES.each { |attributes| ListingCategory.create(attributes) } +seeder.create_if_none(HtmlVariant) do + HtmlVariant.create!( + name: rand(100).to_s, + group: "badge_landing_page", + html: rand(1000).to_s, + success_rate: 0, + published: true, + approved: true, + user_id: User.first.id, + ) +end ############################################################################## -counter += 1 -Rails.logger.info "#{counter}. Creating Listings" +seeder.create_if_none(Badge) do + 5.times do + Badge.create!( + title: "#{Faker::Lorem.word} #{rand(100)}", + description: Faker::Lorem.sentence, + badge_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")), + ) + end -users_in_random_order.each { |user| Credit.add_to(user, rand(100)) } -users = users_in_random_order.to_a - -listings_categories = ListingCategory.pluck(:id) -listings_categories.each.with_index(1) do |category_id, index| - # rotate users if they are less than the categories - user = users.at(index % users.length) - 2.times do - Listing.create!( - user: user, - title: Faker::Lorem.sentence, - body_markdown: Faker::Markdown.random, - location: Faker::Address.city, - organization_id: user.organizations.first&.id, - listing_category_id: category_id, - contact_via_connect: true, - published: true, - bumped_at: Time.current, - tag_list: Tag.order(Arel.sql("RANDOM()")).first(2).pluck(:name), + users_in_random_order.limit(10).each do |user| + user.badge_achievements.create!( + badge: Badge.order(Arel.sql("RANDOM()")).limit(1).take, + rewarding_context_message_markdown: Faker::Markdown.random, ) end end ############################################################################## -counter += 1 -Rails.logger.info "#{counter}. Creating Pages" +seeder.create_if_none(FeedbackMessage) do + mod = User.first -5.times do - Page.create!( - title: Faker::Hacker.say_something_smart, - body_markdown: Faker::Markdown.random, - slug: Faker::Internet.slug, - description: Faker::Books::Dune.quote, - template: %w[contained full_within_layout].sample, + FeedbackMessage.create!( + reporter: User.last, + feedback_type: "spam", + message: Faker::Lorem.sentence, + category: "spam", + status: "Open", ) + + FeedbackMessage.create!( + reporter: mod, + feedback_type: "abuse-reports", + message: Faker::Lorem.sentence, + reported_url: "example.com", + category: "harassment", + status: "Open", + ) + + Reaction.create!( + category: "vomit", + reactable_id: User.last.id, + reactable_type: "User", + user_id: mod.id, + ) + + 3.times do + Reaction.create!( + category: "vomit", + reactable_id: Article.order(Arel.sql("RANDOM()")).first.id, + reactable_type: "Article", + user_id: mod.id, + ) + end +end + +############################################################################## + +seeder.create_if_none(ListingCategory) do + categories = [ + { + slug: "cfp", + cost: 1, + name: "Conference CFP", + rules: "Currently open for proposals, with link to form." + }, + { + slug: "education", + cost: 1, + name: "Education/Courses", + rules: "Educational material and/or schools/bootcamps." + }, + { + slug: "jobs", + cost: 25, + name: "Job Listings", + rules: "Companies offering employment right now." + }, + { + slug: "forsale", + cost: 1, + name: "Stuff for Sale", + rules: "Personally owned physical items for sale." + }, + { + slug: "events", + cost: 1, + name: "Upcoming Events", + rules: "In-person or online events with date included." + }, + { + slug: "misc", + cost: 1, + name: "Miscellaneous", + rules: "Must not fit in any other category." + }, + ].freeze + + categories.each { |attributes| ListingCategory.create(attributes) } +end + +############################################################################## + +seeder.create_if_none(ListingCategory) do + users_in_random_order = User.order(Arel.sql("RANDOM()")) + users_in_random_order.each { |user| Credit.add_to(user, rand(100)) } + users = users_in_random_order.to_a + + listings_categories = ListingCategory.pluck(:id) + listings_categories.each.with_index(1) do |category_id, index| + # rotate users if they are less than the categories + user = users.at(index % users.length) + 2.times do + Listing.create!( + user: user, + title: Faker::Lorem.sentence, + body_markdown: Faker::Markdown.random, + location: Faker::Address.city, + organization_id: user.organizations.first&.id, + listing_category_id: category_id, + contact_via_connect: true, + published: true, + bumped_at: Time.current, + tag_list: Tag.order(Arel.sql("RANDOM()")).first(2).pluck(:name), + ) + end + end +end + +############################################################################## + +seeder.create_if_none(Page) do + 5.times do + Page.create!( + title: Faker::Hacker.say_something_smart, + body_markdown: Faker::Markdown.random, + slug: Faker::Internet.slug, + description: Faker::Books::Dune.quote, + template: %w[contained full_within_layout].sample, + ) + end end ############################################################################## -# rubocop:disable Rails/Output puts <<-ASCII - - ``````````````````````````````````````````````````````````````````````````` ``````````````````````````````````````````````````````````````````````````` ```````````````````````````````````````````````````````````````````````````