Class: Geoname

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
HasGeoLookup
Defined in:
lib/has_geo_lookup/models/geoname.rb

Overview

Geoname model for geographic place names from Geonames.org

This model represents geographic features from the Geonames.org dataset, which provides comprehensive information about populated places, administrative divisions, and geographic features worldwide. Each record includes coordinates, names, administrative codes, and feature classifications.

The Geonames dataset is organized using feature classes and codes that categorize different types of geographic entities (populated places, administrative areas, hydrographic features, etc.).

Examples:

Find populated places in the US

Geoname.where(country_code: "US", feature_class: "P")

Find administrative divisions

Geoname.where(feature_class: "A", feature_code: "ADM2")

See Also:

Constant Summary

Constants included from HasGeoLookup

HasGeoLookup::VERSION

Instance Method Summary collapse

Methods included from HasGeoLookup

#closest_county_or_parish, #closest_metro, #closest_subdivision, #closest_township, #compare_geo_sources, #containing_boundaries, #containing_boundary, #county_or_parish_boundary, #nearest_geonames, #state_or_province_boundary, #subdivision_with_boundary_context, #township_boundary, #validate_and_convert_coordinates, #within_metro

Instance Method Details

#administrative_division?Boolean

Check if this is an administrative division

Returns:

  • (Boolean)

    true if feature_class is "A"



127
128
129
# File 'lib/has_geo_lookup/models/geoname.rb', line 127

def administrative_division?
  feature_class == "A"
end

#administrative_levelString?

Get the administrative level for administrative divisions

Returns:

  • (String, nil)

    Administrative level (ADM1, ADM2, etc.) or nil



133
134
135
136
# File 'lib/has_geo_lookup/models/geoname.rb', line 133

def administrative_level
  return nil unless administrative_division?
  feature_code if feature_code&.start_with?("ADM")
end

#country_code=(value) ⇒ Object

Ensure country codes are stored in uppercase



139
140
141
# File 'lib/has_geo_lookup/models/geoname.rb', line 139

def country_code=(value)
  super(value&.upcase)
end

#display_nameString

Returns a human-readable description of this place

Combines the name with administrative context and country information to provide a comprehensive description suitable for display or logging.

Examples:

geoname.display_name
# => "New York, New York, US (PPL - populated place)"

Returns:

  • (String)

    Formatted description



104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/has_geo_lookup/models/geoname.rb', line 104

def display_name
  parts = [name]
  parts << admin1_name if admin1_name.present?
  parts << admin2_name if admin2_name.present? && admin2_name != admin1_name
  parts << country_code if country_code.present?
  
  description = parts.join(", ")
  
  if feature_code.present?
    description += " (#{feature_code})"
  end
  
  description
end

#distance_to(target_lat, target_lng) ⇒ Float

Calculate distance to coordinates using Haversine formula

This method calculates the great-circle distance between this geoname's coordinates and the provided coordinates using the Haversine formula. Useful for finding nearby places or sorting by distance.

Examples:

geoname.distance_to(40.7128, -74.0060)
# => 245.67 (distance in kilometers)

Parameters:

  • target_lat (Float)

    Target latitude in degrees

  • target_lng (Float)

    Target longitude in degrees

Returns:

  • (Float)

    Distance in kilometers



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/has_geo_lookup/models/geoname.rb', line 76

def distance_to(target_lat, target_lng)
  return nil unless latitude && longitude && target_lat && target_lng

  # Haversine formula
  radius_km = 6371.0
  lat1_rad = latitude * Math::PI / 180
  lat2_rad = target_lat * Math::PI / 180
  delta_lat_rad = (target_lat - latitude) * Math::PI / 180
  delta_lng_rad = (target_lng - longitude) * Math::PI / 180

  a = Math.sin(delta_lat_rad / 2) * Math.sin(delta_lat_rad / 2) +
      Math.cos(lat1_rad) * Math.cos(lat2_rad) *
      Math.sin(delta_lng_rad / 2) * Math.sin(delta_lng_rad / 2)
  
  c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
  radius_km * c
end

#feature_class=(value) ⇒ Object

Ensure feature class is stored in uppercase



144
145
146
# File 'lib/has_geo_lookup/models/geoname.rb', line 144

def feature_class=(value)
  super(value&.upcase)
end

#feature_code=(value) ⇒ Object

Ensure feature code is stored in uppercase



149
150
151
# File 'lib/has_geo_lookup/models/geoname.rb', line 149

def feature_code=(value)
  super(value&.upcase)
end

#populated_place?Boolean

Check if this is a populated place

Returns:

  • (Boolean)

    true if feature_class is "P"



121
122
123
# File 'lib/has_geo_lookup/models/geoname.rb', line 121

def populated_place?
  feature_class == "P"
end