HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyrailsMinor

Seed a database

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
databaseseedstackoverflow

Problem

I'm looking for advice / best practice to avoid doing a deeply nested set of IF/THEN statements in Rails. The intention is to seed a database.

Short version - without specific examples

My basic pattern is 1 .. n

IF(1st_object_exists) THEN
 2nd_object = 1st_object.relationship.create!(args)
 IF (2nd_object) THEN
   3rd_object ... so on & so forth down 9 levels ...
 END
END


Where the issue exists is I have two additional, unrelated relationships which should populate at each step back at each step & potentially 4 or 5 that need to populate.

Long version - with specific examples

Basic setup: each game is a campaign. Each campaign will have players, each player will have a country (each country also has a join table back to the campaign), each country a state...

I'm hoping there's an elegant way of doing this instead without using too many object chains (".")'s, but perfectly happy to do so if that's the only way.

Originally, I was doing Campaign.Players.Countries.create!(args), which errors with not valid method for Countries or Players until I eliminate one or the other. Eliminating this leaves me seeding the relationship value for the other has_many else where though...

I also had tried using the same join tables with models using has_many, through: for this pattern ...

user = User.first
  if(user) then
    campaign = user.campaigns.create!(args)
    if(campaign) then
      new_player = game_instance.players.create!(args)
      if(new_player) then
        new_country = new_player.countries.create!(args)
    if(new_country) then
      new_country.states.create!(args)
    end
  end
end
  end


My models are a bit of a mess but all present ...

There are several primary tables & a join table between each (including a belongs_to matching the has_many's pointed at it from other files)

user.rb

has_many :userplays
  has_many :players, through: :userplays
  has_many  :usercamps
  has_many  :campaigns, through: :usercamps


campaign.rb

Solution

On a technical note create! will always return a valid object (or raise an exception)

What I usually do is put it in a separate method and use an early return:

user = User.first
return unless user
campaign = user.campaigns.create!(args)
return unless campaign
new_player = game_instance.players.create!(args)
return unless new_player
new_country = new_player.countries.create!(args)
return unless new_county
new_country.states.create!(args)


You can combine the return as follows:

user = User.first                                 || return
campaign = user.campaigns.create!(args)           || return 
new_player = game_instance.players.create!(args)  || return
new_country = new_player.countries.create!(args)  || return
new_country.states.create!(args)


Or even

campaign = User.first &. campaigns.create!(args)
return unless campaign

game_instance.players.create!(args)  &.
      countries.create!(args)  &.
      states.create!(args)


But I prefer not to use this programming style

-- Update 1

To clarify by it I mean these lines of code. Depending on what you do following this you might want to not put all the code in the same place.

Code Snippets

user = User.first
return unless user
campaign = user.campaigns.create!(args)
return unless campaign
new_player = game_instance.players.create!(args)
return unless new_player
new_country = new_player.countries.create!(args)
return unless new_county
new_country.states.create!(args)
user = User.first                                 || return
campaign = user.campaigns.create!(args)           || return 
new_player = game_instance.players.create!(args)  || return
new_country = new_player.countries.create!(args)  || return
new_country.states.create!(args)
campaign = User.first &. campaigns.create!(args)
return unless campaign

game_instance.players.create!(args)  &.
      countries.create!(args)  &.
      states.create!(args)

Context

StackExchange Code Review Q#156640, answer score: 2

Revisions (0)

No revisions yet.