Files
nairobi/app/models/geozone.rb
CoslaJohn 5dbe2cbf24 Support FeatureCollection and MultiPolygon in geozones
We're reworking the format validation to correctly interpret feature
collection, feature, and geometry, according to RFC 7946 [1].

Since Leaflet interprets GeoJSON format, we're rendering the GeoJSON as
a layer instead of as a set of points. For that, we're normalizing the
GeoJSON to make sure it contains either a Feature or a
FeatureCollection. We're also adding the Leaflet images to the assets
path so the markers used for point geometries are rendered correctly.

Note we no longer allow a GeoJSON containing a geometry but not a
defined type. Since there might be invalid GeoJSON in existing Consul
Democracy databases, we're normalizing these existing geometry objects
to be part of a feature object.

We're also wrapping the outline points in a FeatureCollection object
because most of the large GIS systems eg ArcGIS, QGIS export geojson as
a complete FeatureCollection.

[1] https://datatracker.ietf.org/doc/html/rfc7946

Co-authored-by: Javi Martín <javim@elretirao.net>
2024-12-23 17:35:33 +01:00

61 lines
1.4 KiB
Ruby

class Geozone < ApplicationRecord
include Graphqlable
has_many :proposals
has_many :debates
has_many :users
has_many :headings, class_name: "Budget::Heading", dependent: :nullify
validates :name, presence: true
validates :geojson, geojson_format: true
scope :public_for_api, -> { all }
def self.names
Geozone.pluck(:name)
end
def safe_to_destroy?
Geozone.reflect_on_all_associations(:has_many).all? do |association|
association.klass.where(geozone: self).empty?
end
end
def outline_points
normalized_geojson&.to_json
end
private
def normalized_geojson
if geojson.present?
parsed_geojson = JSON.parse(geojson)
if parsed_geojson["type"] == "FeatureCollection"
parsed_geojson
elsif parsed_geojson["type"] == "Feature"
wrap_in_feature_collection(parsed_geojson)
elsif parsed_geojson["geometry"]
wrap_in_feature_collection(wrap_in_feature(parsed_geojson["geometry"]))
elsif parsed_geojson["type"] && parsed_geojson["coordinates"]
wrap_in_feature_collection(wrap_in_feature(parsed_geojson))
else
raise ArgumentError, "Invalid GeoJSON fragment"
end
end
end
def wrap_in_feature(geometry)
{
type: "Feature",
geometry: geometry
}
end
def wrap_in_feature_collection(feature)
{
type: "FeatureCollection",
features: [feature]
}
end
end