- Update city initialization to safely access state ID - Use safe navigation operator to prevent potential nil errors This change ensures that if the state is nil, the code will not raise an error when trying to access its ID. It improves the robustness of the city data synchronization process.
204 lines
5.9 KiB
Ruby
204 lines
5.9 KiB
Ruby
# lib/tasks/sync_geo_data.rake
|
|
require "json"
|
|
|
|
namespace :geo do
|
|
desc "Sync geographical data from JSON"
|
|
task sync: :environment do
|
|
# 定义 JSON 文件路径
|
|
base_path = Rails.root.join("lib", "data")
|
|
|
|
# 同步顺序很重要:先同步 Regions -> Subregions -> Countries -> States -> Cities
|
|
sync_regions(base_path)
|
|
sync_subregions(base_path)
|
|
sync_countries(base_path)
|
|
sync_states(base_path)
|
|
sync_cities(base_path)
|
|
end
|
|
|
|
task sync_city: :environment do
|
|
# 定义 JSON 文件路径
|
|
base_path = Rails.root.join("lib", "data")
|
|
sync_cities(base_path)
|
|
end
|
|
|
|
def sync_regions(base_path)
|
|
file_path = base_path.join("regions.json")
|
|
regions = JSON.parse(File.read(file_path))
|
|
sum = regions.count
|
|
count = 1
|
|
|
|
regions.each do |data|
|
|
region = Region.find_or_create_by!(id: data["id"]) do |r|
|
|
r.name = data["name"]
|
|
r.code = data["name"]
|
|
end
|
|
puts "Sync Regions[#{count}/#{sum}]: [#{region.name}]"
|
|
count += 1
|
|
|
|
region.update!(
|
|
name: data["name"],
|
|
code: data["name"],
|
|
translations: data["translations"].to_json.to_s,
|
|
flag: data["flag"] || true,
|
|
wiki_data_id: data["wikiDataId"]
|
|
)
|
|
end
|
|
end
|
|
|
|
def sync_subregions(base_path)
|
|
file_path = base_path.join("subregions.json")
|
|
subregions = JSON.parse(File.read(file_path))
|
|
sum = subregions.count
|
|
count = 1
|
|
|
|
subregions.each do |data|
|
|
region = Region.find_by!(id: data["region_id"])
|
|
subregion = Subregion.find_or_create_by!(id: data["id"]) do |s|
|
|
s.name = data["name"]
|
|
s.region_id = region.id
|
|
end
|
|
puts "Sync Subregions[#{count}/#{sum}]: [#{subregion.name}] region:[#{region.name}]"
|
|
count += 1
|
|
|
|
subregion.update!(
|
|
translations: data["translations"].to_json,
|
|
flag: data["flag"] || true,
|
|
wiki_data_id: data["wikiDataId"]
|
|
)
|
|
end
|
|
end
|
|
|
|
def sync_countries(base_path)
|
|
file_path = base_path.join("countries.json")
|
|
countries = JSON.parse(File.read(file_path))
|
|
sum = countries.count
|
|
count = 1
|
|
|
|
countries.each do |data|
|
|
# 处理 Region
|
|
region = if data["region_id"]
|
|
Region.find_by(id: data["region_id"])
|
|
elsif data["region"]
|
|
Region.find_by(name: data["region"])
|
|
end
|
|
|
|
# 处理 Subregion
|
|
subregion = nil
|
|
if data["subregion_id"].present?
|
|
subregion = Subregion.find_by(id: data["subregion_id"])
|
|
elsif data["subregion"].present?
|
|
subregion = Subregion.find_by(name: data["subregion"])
|
|
end
|
|
puts "Syncing Country[#{count}/#{sum}] [#{data["name"]}] region: [#{region&.name}] subregion: [#{data["subregion"]}]"
|
|
count += 1
|
|
|
|
# 查找或初始化 Country
|
|
country = Country.find_or_create_by!(code: data["iso2"]) do |c|
|
|
c.name = data["name"]
|
|
end
|
|
|
|
# 更新 Country 属性
|
|
country.update!(
|
|
name: data["name"],
|
|
iso3: data["iso3"],
|
|
numeric_code: data["numeric_code"],
|
|
iso2: data["iso2"],
|
|
code: data["iso2"],
|
|
phonecode: data["phonecode"],
|
|
capital: data["capital"],
|
|
currency: data["currency"],
|
|
currency_name: data["currency_name"],
|
|
currency_symbol: data["currency_symbol"],
|
|
tld: data["tld"],
|
|
native: data["native"],
|
|
nationality: data["nationality"],
|
|
timezones: data["timezones"].to_json,
|
|
translations: data["translations"].to_json,
|
|
latitude: data["latitude"],
|
|
longitude: data["longitude"],
|
|
emoji: data["emoji"],
|
|
emoji_u: data["emojiU"],
|
|
flag: data["flag"] || true,
|
|
wiki_data_id: data["wikiDataId"]
|
|
)
|
|
country.update!(region: region) if region != nil
|
|
country.update!(subregion: subregion) if subregion != nil
|
|
end
|
|
end
|
|
|
|
def sync_states(base_path)
|
|
file_path = base_path.join("states.json")
|
|
states = JSON.parse(File.read(file_path))
|
|
sum = states.count
|
|
count = 1
|
|
|
|
states.each do |data|
|
|
puts "Syncing State[#{count}/#{sum}] [#{data["name"]}] country:[#{data["country_name"]}]"
|
|
count += 1
|
|
|
|
country = Country.find_by!(code: data["country_code"])
|
|
|
|
state = State.find_or_create_by!(name: data["name"]) do |s|
|
|
s.country_id = country&.id
|
|
s.country_code = country&.code
|
|
end
|
|
|
|
state.update!(
|
|
country_id: country&.id,
|
|
country_code: country&.code,
|
|
fips_code: data["fips_code"],
|
|
iso2: data["iso2"],
|
|
code: data["state_code"],
|
|
state_type: data["type"],
|
|
level: data["level"],
|
|
parent_id: data["parent_id"],
|
|
latitude: data["latitude"],
|
|
longitude: data["longitude"],
|
|
flag: data["flag"] || true,
|
|
wiki_data_id: data["wikiDataId"]
|
|
)
|
|
end
|
|
end
|
|
|
|
def sync_cities(base_path)
|
|
file_path = base_path.join("cities.json")
|
|
cities = JSON.parse(File.read(file_path))
|
|
sum = cities.count
|
|
count = 1
|
|
|
|
cities.each do |data|
|
|
country = Country.find_by!(code: data["country_code"])
|
|
state = State.find_by(code: data["state_code"])
|
|
|
|
# 使用多个属性来确保唯一性
|
|
city = City.find_or_initialize_by(
|
|
name: data["name"],
|
|
country_id: country.id,
|
|
state_id: state&.id
|
|
)
|
|
|
|
# 更新或设置城市属性
|
|
city.assign_attributes(
|
|
country_code: country.code,
|
|
latitude: data["latitude"],
|
|
longitude: data["longitude"],
|
|
state_id: state&.id,
|
|
state_code: state&.code,
|
|
flag: data["flag"] || true,
|
|
wiki_data_id: data["wikiDataId"],
|
|
active: city.active || false,
|
|
priority: city.priority || 10
|
|
)
|
|
|
|
# 保存城市
|
|
if city.save
|
|
puts "Syncing City[#{count}/#{sum}] [#{data["name"]}] Country:[#{country.name}] State: [#{state&.name}] Lat:[#{data["latitude"]}] Lon:[#{data["longitude"]}]"
|
|
else
|
|
puts "Error saving city: #{city.errors.full_messages.join(", ")}"
|
|
end
|
|
|
|
count += 1
|
|
end
|
|
end
|
|
end
|