Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow seeding in production with environment variable adjustment #581

Merged
merged 4 commits into from
Dec 12, 2024

Conversation

thatguyinabeanie
Copy link
Owner

@thatguyinabeanie thatguyinabeanie commented Dec 12, 2024

Modify the seeding logic to allow data seeding in production based on an environment variable, and update the handling of allowed request origins to prevent errors when the variable is not set.

Summary by CodeRabbit

  • New Features

    • Seeding process now runs in all environments, enhancing flexibility.
    • Default pronouns set to "they/them" for new accounts.
    • At least 50 accounts will be created during seeding.
    • Tournament creation logic updated to ensure tournaments are published by default.
    • Pokémon data seeding now includes validation checks for species and position attributes.
  • Bug Fixes

    • Improved error handling for Pokémon data validation.
  • Configuration Updates

    • Enhanced Action Cable configuration to prevent potential errors in production.

@thatguyinabeanie thatguyinabeanie enabled auto-merge (squash) December 12, 2024 19:12
Copy link

coderabbitai bot commented Dec 12, 2024

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 rubocop (1.69.1)
db/seeds.rb

There was an error parsing Gemfile: windows is not a valid platform. The available options are: [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :ruby_25, :ruby_26, :mri, :mri_18, :mri_19, :mri_20, :mri_21, :mri_22, :mri_23, :mri_24, :mri_25, :mri_26, :rbx, :truffleruby, :jruby, :jruby_18, :jruby_19, :mswin, :mswin_18, :mswin_19, :mswin_20, :mswin_21, :mswin_22, :mswin_23, :mswin_24, :mswin_25, :mswin_26, :mswin64, :mswin64_19, :mswin64_20, :mswin64_21, :mswin64_22, :mswin64_23, :mswin64_24, :mswin64_25, :mswin64_26, :mingw, :mingw_18, :mingw_19, :mingw_20, :mingw_21, :mingw_22, :mingw_23, :mingw_24, :mingw_25, :mingw_26, :x64_mingw, :x64_mingw_20, :x64_mingw_21, :x64_mingw_22, :x64_mingw_23, :x64_mingw_24, :x64_mingw_25, :x64_mingw_26]. Bundler cannot continue.

Walkthrough

This pull request introduces updates to two key files: config/environments/production.rb and db/seeds.rb. In the production configuration, it modifies how allowed origins for Action Cable are set, using a safe navigation operator to avoid errors if the environment variable is nil. The seeding file removes checks for the production environment, adjusts conditions for skipping seeds, and enhances account creation logic by setting default pronouns. It also ensures a minimum of 50 accounts are created and validates Pokémon data before seeding, keeping data integrity intact.

Changes

File Change Summary
config/environments/production.rb Updated config.action_cable.allowed_request_origins to use safe navigation operator to prevent NoMethodError when ENV["ACTION_CABLE_ALLOWED_ORIGINS"] is nil.
db/seeds.rb - Removed production environment check for seeding.
- Changed seed skipping condition to string comparison.
- Updated create_account to default pronouns to "they/them".
- Ensured at least 50 accounts are created.
- Validated Pokémon data before seeding, adding error handling.

Possibly related PRs


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Experiment)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

sonarcloud bot commented Dec 12, 2024

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (5)
db/seeds.rb (5)

17-20: Hey, let's make the skip message more informative! 📢

The string comparison is great, but we could make the skip message more helpful by including the environment variable name.

Here's a suggestion:

 if ENV.fetch("SKIP_SEEDS", "false") == "true"
-  puts("Skipping seeding data.")
+  puts("Skipping seeds (SKIP_SEEDS=true)")
   exit
 end

Line range hint 28-52: Let's wrap this in a transaction for extra safety! 🔒

The account and profile creation logic looks good, but we should ensure it's atomic.

Here's how we could improve it:

 def create_account(username: nil, first_name: nil, last_name: nil, email: nil, pronouns: nil, admin: false)
   first_name ||= Faker::Name.first_name
   last_name ||= Faker::Name.last_name
   username ||= Faker::Internet.unique.username
   email ||= "#{username}@beanie.com"
   pronouns ||= "they/them"

   attrs = {
     email:,
     first_name:,
     last_name:,
     admin:,
     pronouns:
   }

-  # Check if Account already exists
-  account = Account.find_or_create_by_profile_username(username:, **attrs)
-
-  # Check if profile with the given username already exists
-  profile = Profile.find_or_create_by!(username:) do |p|
-    p.account = account
-  end
-
-  account.update!(default_profile: profile)
+  Account.transaction do
+    account = Account.find_or_create_by_profile_username(username:, **attrs)
+    profile = Profile.find_or_create_by!(username:) do |p|
+      p.account = account
+    end
+    account.update!(default_profile: profile)
+  end

   account
 end

Line range hint 54-76: Let's make those magic numbers configurable! ✨

The tournament creation looks solid, but we've got some magic numbers that could be configuration constants.

Here's a suggestion:

+# At the top of the file
+TOURNAMENT_CONFIG = {
+  check_in_buffer: 1.hour,
+  default_swiss_rounds: 5
+}.freeze

 def create_tournament(name:, organization:, format:, game:, start_at:, end_at:)
   Tournament.find_or_create_by!(name:, organization:, format:, game:) do |tournament|
     tournament.published = true
     tournament.start_at = start_at
-    tournament.check_in_start_at = start_at - 1.hour
+    tournament.check_in_start_at = start_at - TOURNAMENT_CONFIG[:check_in_buffer]
     tournament.end_at = end_at

     tournament.phases << Phases::Swiss.create!(
       name: "#{tournament.name} - Swiss Rounds",
       tournament:,
-      number_of_rounds: 5,
+      number_of_rounds: TOURNAMENT_CONFIG[:default_swiss_rounds],
       order: 0
     )

Line range hint 106-110: Let's speed up those account creations! 🚀

When creating multiple accounts, we could use bulk insert for better performance.

Here's how we could improve it:

 accounts = Account.all
 if accounts.count < 50
   needed_accounts = 50 - accounts.count
-  accounts = accounts + needed_accounts.times.map { |i| create_account(username: "seed_user_#{i}") }
+  new_accounts = needed_accounts.times.map do |i|
+    username = "seed_user_#{i}"
+    {
+      email: "#{username}@beanie.com",
+      first_name: Faker::Name.first_name,
+      last_name: Faker::Name.last_name,
+      pronouns: "they/them",
+      created_at: Time.current,
+      updated_at: Time.current
+    }
+  end
+  accounts = accounts + Account.insert_all!(new_accounts)
 end

Line range hint 133-134: Let's beef up that Pokemon validation! 🎮

The current validation is good, but we could make it more thorough.

Here's a more comprehensive validation:

-  raise "Invalid pokemon data" unless pokemon_data.all? { |p| p[:species].present? && p[:position].present? }
+  pokemon_data.each do |pokemon|
+    missing_fields = []
+    %i[species position ability tera_type nature].each do |field|
+      missing_fields << field unless pokemon[field].present?
+    end
+    
+    if missing_fields.any?
+      raise "Invalid pokemon data: #{pokemon[:species] || 'Unknown'} missing #{missing_fields.join(', ')}"
+    end
+    
+    unless (1..6).include?(pokemon[:position])
+      raise "Invalid position: #{pokemon[:position]} for #{pokemon[:species]}"
+    end
+  end
🛑 Comments failed to post (1)
config/environments/production.rb (1)

42-42: 💡 Codebase verification

Hey there! We found another Action Cable ENV usage that could use some love! 🛡️

I spotted that config.action_cable.url = ENV["ACTION_CABLE_URL"] in production.rb isn't using the safe navigation operator, while its sibling allowed_request_origins is. Let's keep the safety measures consistent!

  • config/environments/production.rb: Add & to ENV["ACTION_CABLE_URL"] to match the defensive style used for allowed_request_origins
🔗 Analysis chain

Nice defensive programming! Let's verify the behavior 🛡️

The safe navigation operator (&.) is a great addition here! It'll prevent those pesky nil errors when ACTION_CABLE_ALLOWED_ORIGINS isn't set.

Let's make sure we're handling all the edge cases:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any other Action Cable related environment variables that might need similar protection

rg -g '*.rb' 'ENV\["ACTION_CABLE.*"\](?!\s*&)'

Length of output: 306


Script:

#!/bin/bash
# Let's try a simpler search for Action Cable config patterns
rg --pcre2 'ENV\["ACTION_CABLE' -g '*.rb'

# Also search with ast-grep to catch any ENV usage with Action Cable
ast-grep --pattern 'ENV["ACTION_CABLE$_"]'

# And let's check for any other Action Cable config patterns
rg 'config\.action_cable' -g '*.rb'

Length of output: 879

Copy link

codecov bot commented Dec 12, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 93.77%. Comparing base (9d367ac) to head (84be2a1).
Report is 1 commits behind head on main.

✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #581   +/-   ##
=======================================
  Coverage   93.77%   93.77%           
=======================================
  Files          72       72           
  Lines        1736     1736           
  Branches      306      306           
=======================================
  Hits         1628     1628           
  Misses        108      108           
Flag Coverage Δ
rspec 93.77% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (3)
db/seeds.rb (3)

Line range hint 28-53: The account creation looks good, but let's make it bulletproof! 🛡️

The logic is solid, but we could add some basic validation to ensure the email format is correct and handle potential race conditions in the find_or_create pattern.

Here's a suggested improvement:

 def create_account(username: nil, first_name: nil, last_name: nil, email: nil, pronouns: nil, admin: false)
   first_name ||= Faker::Name.first_name
   last_name ||= Faker::Name.last_name
   username ||= Faker::Internet.unique.username
   email ||= "#{username}@beanie.com"
   pronouns ||= "they/them"
+
+  # Basic email format validation
+  raise ArgumentError, "Invalid email format" unless email =~ URI::MailTo::EMAIL_REGEXP
 
   attrs = {
     email:,
     first_name:,
     last_name:,
     admin:,
     pronouns:
   }
 
-  # Check if Account already exists
-  account = Account.find_or_create_by_profile_username(username:, **attrs)
+  # Use transaction to prevent race conditions
+  Account.transaction do
+    account = Account.find_or_create_by_profile_username(username:, **attrs)
 
-  # Check if profile with the given username already exists
-  profile = Profile.find_or_create_by!(username:) do |p|
-    p.account = account
-  end
+    # Check if profile with the given username already exists
+    profile = Profile.find_or_create_by!(username:) do |p|
+      p.account = account
+    end
 
-  account.update!(default_profile: profile)
-  account
+    account.update!(default_profile: profile)
+    account
+  end
 end

Line range hint 55-71: The tournament setup looks neat! Just one tiny suggestion... ⏰

The tournament creation logic is solid, but we might want to add some date validation to ensure start_at is before end_at and that check_in_start_at makes sense.

Here's a small improvement:

 def create_tournament(name:, organization:, format:, game:, start_at:, end_at:)
+  raise ArgumentError, "end_at must be after start_at" if end_at <= start_at
+  
   Tournament.find_or_create_by!(name:, organization:, format:, game:) do |tournament|
     tournament.published = true
     tournament.start_at = start_at
     tournament.check_in_start_at = start_at - 1.hour
     tournament.end_at = end_at

Line range hint 115-146: Looking good! Let's make the Pokémon team creation even more robust! 🎮

The Pokémon data validation is a great addition! However, the nested creation logic could be simplified and made more resilient to failures.

Here's a suggested improvement:

-  # Validate pokemon_data before proceeding
-  raise "Invalid pokemon data" unless pokemon_data.all? { |p| p[:species].present? && p[:position].present? }
+  # Enhanced validation with specific error messages
+  pokemon_data.each do |pokemon|
+    missing = [:species, :position, :ability, :tera_type, :nature].select { |key| pokemon[key].blank? }
+    raise ArgumentError, "Missing required fields: #{missing.join(', ')}" if missing.any?
+  end

   tour.players = accounts_with_profiles.map do |account|
     next if tour.players.exists?(account:)
 
-    tour.players.create!(account:, in_game_name: account.default_profile.username, profile: account.default_profile).tap do |player|
-      team = PokemonTeam.create(profile: player.profile, format:, game:, published: true).tap do |pokemon_team|
+    # Use transaction to ensure data consistency
+    Player.transaction do
+      player = tour.players.create!(
+        account:,
+        in_game_name: account.default_profile.username,
+        profile: account.default_profile
+      )
+      
+      team = PokemonTeam.create!(
+        profile: player.profile,
+        format:,
+        game:,
+        published: true
+      )
+      
+      # Bulk create Pokémon for better performance
+      pokemon_records = pokemon_data.map do |pokemon|
+        pokemon.merge(pokemon_team: team)
+      end
+      Pokemon.create!(pokemon_records)
 
-        pokemon_team.pokemon = pokemon_data.map { |pokemon| Pokemon.create!(pokemon_team:, **pokemon) }
-        pokemon_team.format = format
-        pokemon_team.game = game
-        pokemon_team.save!
-      end
-
-      player.pokemon_team_id = team.id
-      player.save!
+      player.update!(pokemon_team_id: team.id)
+      player
     end
   end

This refactor:

  1. Adds more specific validation error messages
  2. Uses transactions for data consistency
  3. Improves performance with bulk creation
  4. Simplifies the nested creation logic
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 289cef1 and 84be2a1.

📒 Files selected for processing (1)
  • db/seeds.rb (1 hunks)
🔇 Additional comments (2)
db/seeds.rb (2)

17-18: Hey there! Nice update to the environment variable check! 👋

The change from boolean to string comparison ("false") is a solid improvement since environment variables are always strings. This makes the code more reliable and prevents any unexpected type coercion issues.


Line range hint 1-146: Overall, these changes look great for enabling production seeding! 🎉

The modifications align perfectly with the PR objectives of allowing seeding in production environments. The code maintains data integrity while providing flexibility through environment variables.

Just a heads up though - we should verify that the seeding process won't interfere with existing production data.

Let's check for any existing production safeguards:

✅ Verification successful

Let me check for any potential data integrity concerns in the seeding logic.


Hey there! The seeding setup looks safe and sound! 🌱

The code has some really nice safeguards built in:

  • Uses find_or_create patterns throughout, preventing duplicate records
  • Has a handy SKIP_SEEDS environment variable as an emergency brake
  • Production database is properly isolated with its own URL configuration
  • Data creation is idempotent and doesn't mess with existing records

Plus, there's a thoughtful touch with the reset_column_information calls before seeding, which helps avoid any schema-related hiccups. The seeding process will play nice with your production data! 👍

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Look for production environment checks or safeguards
rg -i "production|environment" config/

Length of output: 2773


Script:

#!/bin/bash
# Look for find_or_create patterns and data protection mechanisms
rg -B2 -A2 "find_or_create" db/seeds.rb

# Check for any database protection or environment specific configurations
rg -i "database|production" config/database.yml

Length of output: 2396

@thatguyinabeanie thatguyinabeanie merged commit e37a4bc into main Dec 12, 2024
18 checks passed
@thatguyinabeanie thatguyinabeanie deleted the prod-seeds branch December 12, 2024 19:15
@coderabbitai coderabbitai bot mentioned this pull request Dec 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant