diff --git a/app/jobs/data_migrations/migrate_places_lonlat_job.rb b/app/jobs/data_migrations/migrate_places_lonlat_job.rb new file mode 100644 index 00000000..e4ba1e33 --- /dev/null +++ b/app/jobs/data_migrations/migrate_places_lonlat_job.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class DataMigrations::MigratePlacesLonlatJob < ApplicationJob + queue_as :default + + def perform(user_id) + user = User.find(user_id) + + # rubocop:disable Rails/SkipsModelValidations + user.places.update_all('lonlat = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)') + # rubocop:enable Rails/SkipsModelValidations + end +end diff --git a/app/models/place.rb b/app/models/place.rb index 2ed0aa2d..c7cbacef 100644 --- a/app/models/place.rb +++ b/app/models/place.rb @@ -1,17 +1,27 @@ # frozen_string_literal: true class Place < ApplicationRecord - DEFAULT_NAME = 'Suggested place' - reverse_geocoded_by :latitude, :longitude + include Nearable + include Distanceable - validates :name, :longitude, :latitude, presence: true + DEFAULT_NAME = 'Suggested place' + + validates :name, :lonlat, presence: true has_many :visits, dependent: :destroy has_many :place_visits, dependent: :destroy - has_many :suggested_visits, through: :place_visits, source: :visit + has_many :suggested_visits, -> { distinct }, through: :place_visits, source: :visit enum :source, { manual: 0, photon: 1 } + def lon + lonlat.x + end + + def lat + lonlat.y + end + def async_reverse_geocode return unless DawarichSettings.reverse_geocoding_enabled? diff --git a/app/services/reverse_geocoding/places/fetch_data.rb b/app/services/reverse_geocoding/places/fetch_data.rb index 5c930b5a..d6b5c059 100644 --- a/app/services/reverse_geocoding/places/fetch_data.rb +++ b/app/services/reverse_geocoding/places/fetch_data.rb @@ -79,8 +79,7 @@ class ReverseGeocoding::Places::FetchData return found_place if found_place.present? Place.find_or_initialize_by( - latitude: place_data['geometry']['coordinates'][1].to_f.round(5), - longitude: place_data['geometry']['coordinates'][0].to_f.round(5) + lonlat: "POINT(#{place_data['geometry']['coordinates'][0].to_f.round(5)} #{place_data['geometry']['coordinates'][1].to_f.round(5)})" ) end @@ -97,7 +96,7 @@ class ReverseGeocoding::Places::FetchData def reverse_geocoded_places data = Geocoder.search( - [place.latitude, place.longitude], + [place.lat, place.lon], limit: 10, distance_sort: true, radius: 1, diff --git a/app/services/visits/smart_detect.rb b/app/services/visits/smart_detect.rb index 0a337230..8ae6759c 100644 --- a/app/services/visits/smart_detect.rb +++ b/app/services/visits/smart_detect.rb @@ -351,8 +351,7 @@ class Visits::SmartDetect nearby_organizations.each do |org| Place.create!( name: org[:name], - latitude: org[:latitude], - longitude: org[:longitude], + lonlat: "POINT(#{org[:longitude]} #{org[:latitude]})", city: org[:city], country: org[:country], geodata: org[:geodata], diff --git a/db/data/20250303194123_migrate_places_lonlat.rb b/db/data/20250303194123_migrate_places_lonlat.rb new file mode 100644 index 00000000..168eb2ca --- /dev/null +++ b/db/data/20250303194123_migrate_places_lonlat.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class MigratePlacesLonlat < ActiveRecord::Migration[8.0] + def up + User.find_each do |user| + DataMigrations::MigratePlacesLonlatJob.perform_later(user.id) + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/migrate/20250303194009_add_lonlat_to_places.rb b/db/migrate/20250303194009_add_lonlat_to_places.rb new file mode 100644 index 00000000..1cd8a76c --- /dev/null +++ b/db/migrate/20250303194009_add_lonlat_to_places.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddLonlatToPlaces < ActiveRecord::Migration[8.0] + def change + add_column :places, :lonlat, :st_point, geographic: true + end +end diff --git a/db/migrate/20250303194043_add_lonlat_index_to_places.rb b/db/migrate/20250303194043_add_lonlat_index_to_places.rb new file mode 100644 index 00000000..bef95a41 --- /dev/null +++ b/db/migrate/20250303194043_add_lonlat_index_to_places.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddLonlatIndexToPlaces < ActiveRecord::Migration[8.0] + disable_ddl_transaction! + + def change + add_index :places, :lonlat, using: :gist, algorithm: :concurrently + end +end diff --git a/db/schema.rb b/db/schema.rb index eccd2a45..562e417c 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_21_194509) do +ActiveRecord::Schema[8.0].define(version: 2025_03_03_194043) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" enable_extension "postgis" @@ -125,6 +125,8 @@ ActiveRecord::Schema[8.0].define(version: 2025_02_21_194509) do t.datetime "reverse_geocoded_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.geography "lonlat", limit: {srid: 4326, type: "st_point", geographic: true} + t.index ["lonlat"], name: "index_places_on_lonlat", using: :gist end create_table "points", force: :cascade do |t| diff --git a/spec/jobs/data_migrations/migrate_places_lonlat_job_spec.rb b/spec/jobs/data_migrations/migrate_places_lonlat_job_spec.rb new file mode 100644 index 00000000..8e2e1bed --- /dev/null +++ b/spec/jobs/data_migrations/migrate_places_lonlat_job_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe DataMigrations::MigratePlacesLonlatJob, type: :job do + pending "add some examples to (or delete) #{__FILE__}" +end