From ca3691004f286ab7f010b923b32b9c0d9bb59752 Mon Sep 17 00:00:00 2001 From: songtianlun Date: Sat, 15 Feb 2025 16:51:36 +0800 Subject: [PATCH] feat: Convert country timezones to JSONB format - Changed `timezones` attribute from text to JSONB in `Country`. - Updated related model methods to handle JSONB data. - Added a migration to convert existing timezone data. - Used safe navigation operators to prevent errors. This change improves the storage and management of timezone information by using the JSONB data type. It includes data migration to handle existing timezone data. --- app/models/city.rb | 2 +- app/models/country.rb | 2 + app/models/weather_art.rb | 2 +- .../batch_generate_weather_arts_worker.rb | 2 +- ...84540_convert_country_timezones_to_json.rb | 42 +++++++++++++++++++ db/schema.rb | 6 +-- 6 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20250215084540_convert_country_timezones_to_json.rb diff --git a/app/models/city.rb b/app/models/city.rb index 18fb0a7..456e9f4 100644 --- a/app/models/city.rb +++ b/app/models/city.rb @@ -218,7 +218,7 @@ class City < ApplicationRecord def formatted_current_time(type = :date, use_local_timezone = true) # 获取时区 timezone_info = self.country&.timezones.present? ? - eval(self.country.timezones).first : + country&.timezones&.first : { "zoneName" => "UTC", "gmtOffsetName" => "UTC+00:00" } # 设置时区对象 diff --git a/app/models/country.rb b/app/models/country.rb index 81f3da5..e79b9e2 100644 --- a/app/models/country.rb +++ b/app/models/country.rb @@ -11,6 +11,8 @@ class Country < ApplicationRecord validates :code, presence: true, uniqueness: true validates :iso2, uniqueness: true, allow_blank: true + attribute :timezones, :jsonb + def to_s name end diff --git a/app/models/weather_art.rb b/app/models/weather_art.rb index 01b3422..1149879 100644 --- a/app/models/weather_art.rb +++ b/app/models/weather_art.rb @@ -71,7 +71,7 @@ class WeatherArt < ApplicationRecord def formatted_time(type = :date, use_local_timezone = false) # 获取时区 timezone_info = self.city&.country&.timezones.present? ? - eval(self.city.country.timezones).first : + self.city.country&.timezones&.first : { "zoneName" => "UTC", "gmtOffsetName" => "UTC+00:00" } # 设置时区对象 diff --git a/app/workers/batch_generate_weather_arts_worker.rb b/app/workers/batch_generate_weather_arts_worker.rb index 8a285a6..86c9952 100644 --- a/app/workers/batch_generate_weather_arts_worker.rb +++ b/app/workers/batch_generate_weather_arts_worker.rb @@ -62,7 +62,7 @@ class BatchGenerateWeatherArtsWorker def get_local_time(city) return Time.current unless city - timezone_info = eval(city.country.timezones).first + timezone_info = city.country&.timezones&.first return Time.current unless timezone_info timezone = ActiveSupport::TimeZone[timezone_info["zoneName"]] || diff --git a/db/migrate/20250215084540_convert_country_timezones_to_json.rb b/db/migrate/20250215084540_convert_country_timezones_to_json.rb new file mode 100644 index 0000000..2fea9f3 --- /dev/null +++ b/db/migrate/20250215084540_convert_country_timezones_to_json.rb @@ -0,0 +1,42 @@ +class ConvertCountryTimezonesToJson < ActiveRecord::Migration[8.0] + def up + # 1. 首先添加一个临时列 + add_column :countries, :timezones_json, :jsonb + + # 2. 转换现有数据 + Country.find_each do |country| + if country.timezones.present? + begin + # 尝试解析现有的 timezones 字符串 + parsed_timezones = eval(country.timezones) # 这里使用 eval 是为了处理历史数据 + country.update_column(:timezones_json, parsed_timezones) + rescue => e + puts "Error converting timezones for country #{country.id}: #{e.message}" + # 设置默认值 + country.update_column(:timezones_json, [{"zoneName" => "UTC", "gmtOffsetName" => "UTC+00:00"}]) + end + else + # 设置默认值 + country.update_column(:timezones_json, [{"zoneName" => "UTC", "gmtOffsetName" => "UTC+00:00"}]) + end + end + + # 3. 删除旧列并重命名新列 + remove_column :countries, :timezones + rename_column :countries, :timezones_json, :timezones + end + + def down + # 回滚操作 + add_column :countries, :timezones_string, :text + + Country.find_each do |country| + if country.timezones.present? + country.update_column(:timezones_string, country.timezones.to_s) + end + end + + remove_column :countries, :timezones + rename_column :countries, :timezones_string, :timezones + end +end diff --git a/db/schema.rb b/db/schema.rb index 8336a65..79bca9c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_02_11_035423) do +ActiveRecord::Schema[8.0].define(version: 2025_02_15_084540) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" @@ -120,7 +120,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_02_11_035423) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "slug" - t.integer "country_id", null: false + t.integer "country_id" t.string "state_code" t.string "country_code" t.boolean "flag", default: true @@ -150,7 +150,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_02_11_035423) do t.string "native" t.string "subregion" t.string "nationality" - t.text "timezones" t.text "translations" t.decimal "latitude", precision: 10, scale: 8 t.decimal "longitude", precision: 11, scale: 8 @@ -159,6 +158,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_02_11_035423) do t.boolean "flag", default: true t.string "wiki_data_id" t.bigint "subregion_id" + t.jsonb "timezones" t.index ["code"], name: "index_countries_on_code", unique: true t.index ["region_id"], name: "index_countries_on_region_id" t.index ["slug"], name: "index_countries_on_slug", unique: true