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

Adding seeds for testing and staging purposes: One map, several layers… #376

Open
wants to merge 4 commits into
base: feature-api-optimization
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 90 additions & 1 deletion db/seeds.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
require 'json'

# Minimal data to have a admin user

Group.find_or_create_by( title: 'Admins' )

Expand All @@ -8,4 +11,90 @@
user.role = 'admin'
user.group = Group.find_by( title: 'Admins' )
puts 'Created a first group and a user'
end
end



module DatabaseSeeding
Copy link
Collaborator

Choose a reason for hiding this comment

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

Langer Nitpick vorraus:

Warum braucht es hier ein Modul mit einer Klasse, welche nur aus self Methoden besteht? Grundsätzlch sollten Module und Klassen in der von Rails vorgesehenen Ordnerstruktur abgelegt werden und das ist hier nicht der Fall.

Hintergrund: Ihr arbeitet augenscheinlich noch mit dem :classic Loader aus Rails 5.1. Mit Rails 7 ist der nicht mehr verfügbar, dann gibts nur noch den wesentlich schnelleren (und strikteren) Zeitwerk Loader: https://guides.rubyonrails.org/v7.0/classic_to_zeitwerk_howto.html

Solange die referenzierten Klassen in der Gleichen Datei sind wird sich auch Zeitwerk nicht daran verschlucken, aber es wird über unerwartete Namen in unerwarteten Dateien warnen. Und in diesem konkreten Fall kann man ja auch mit "normalen" Funktionen für das Seeding gut leben?

class MapSeeder
def self.seed_map_structure(json_file_path )
json_data = File.read(Rails.root.join('db', 'seeds', json_file_path))
map_data = JSON.parse(json_data)

ActiveRecord::Base.transaction do
# Create or update the map
map = create_or_update_map(map_data['map'])

# Process layers
process_layers(map, map_data['map']['layer'])
rescue StandardError => e
puts "Error seeding data: #{e.message}"
puts e.backtrace
raise ActiveRecord::Rollback
end
end


def self.create_or_update_map(map_data)
map_attributes = map_data.except('layer')

# prepare the map attributes
map_attributes.delete_if { |_, v| v.nil? }
group = Group.find_by( title: 'Admins' )
map_attributes['group_id'] = group.id
map_attributes.delete('owner')

if existing_map = Map.find_by(title: map_attributes['title'])
existing_map.tap { |map| map.update!(map_attributes) }
else
Map.create!(map_attributes)
end.tap { |map| puts "Processed Map: #{map_attributes['title']}" }
end

def self.process_layers(map, layers)
return unless layers.is_a?(Array)

layers.each do |layer_data|
layer = create_or_update_layer(map, layer_data)
process_places(layer, layer_data['places'])
end
end

def self.create_or_update_layer(map, layer_data)
layer_attributes = layer_data.except('places').except('places_with_relations')
layer_attributes['map_id'] = map.id
layer_attributes.delete_if { |_, v| v.nil? }

if existing_layer = Layer.find_by(id: layer_attributes['id'])
existing_layer.tap { |layer| layer.update!(layer_attributes) }
else
Layer.create!(layer_attributes)
end.tap { |layer| puts "-- Processed Layer: #{layer_attributes['title']}" }
end

def self.process_places(layer, places)
return unless places.is_a?(Array)

places.each do |place_data|
create_or_update_place(layer, place_data)
end
end

def self.create_or_update_place(layer, place_data)
place_attributes = place_data.clone
place_attributes['layer_id'] = layer.id

# Filter attributes to only include those that exist in the Place model
valid_attributes = place_attributes.slice(*Place.column_names)

if existing_place = Place.find_by(id: valid_attributes['id'])
existing_place.tap { |place| place.update!(valid_attributes) }
else
Place.create!(valid_attributes)
end.tap { |place| puts "---- Processed Place: #{place.title}" }
end
end
end # module DatabaseSeeding

# Seed the database with a sample dataset of public parks in Hamburg West
DatabaseSeeding::MapSeeder.seed_map_structure('public-parks-and-greens-in-hamburg-west.json')
Loading