2

Geocoder gem has been working great if I provide a valid address. But if address is invalid it fails to geocode.

How can I geocode by postal code if geocoding by full address fails?

geocoded_by :address
after_validation :geocode

def address
  [street, city, province, country, postal_code].compact.join(", ")
end

Any ideas?

Thanks

jeffdill2
  • 3,968
  • 2
  • 30
  • 47
Ajit Singh
  • 63
  • 8

3 Answers3

1

Unfortunately, it's a bit hacky, but you'll have to override the geocode method. Something like this should do the trick:

# Override Geocoder's `geocode` method
def geocode
  # Initially just call the original method as intended.
  super

  # Check to see if geocoding failed.
  if latitude.blank? && longitude.blank?
    # Now manually set the `user_address` key to only `postal_code`, instead of the original value of `address`.
    self.class.geocoder_options[:user_address] = postal_code 

    # Now call the original method again.
    super 
  end
end

I might open a PR on the gem – your problem is very interesting. Some kind of fallback option would definitely be super useful. :-)

jeffdill2
  • 3,968
  • 2
  • 30
  • 47
1

I end up using a different solution. Not sure if this is the best way to handle it but:

after_validation :geocode_address

def geocode_address
  results = Geocoder.search(full_address)
  if results.empty?
    postal_code_search = Geocoder.search(postal_code)
    if !postal_code_search.empty?
      lat_long = postal_code_search.first.coordinates
    end
  else
    lat_long = results.first.coordinates
  end
  if lat_long && !lat_long.empty?
    self.latitude = lat_long[0]
    self.longitude = lat_long[1]
  end
end
Ajit Singh
  • 63
  • 8
0

I had the same issue.

Software Version
Ruby v2.6.6
Rails v5.2.5
Geocoder v1.6.4

My approach was to give the geocode_by method a block, as mentioned in the documentation section Custom Result Handling.

In my case I ended up with the following piece of code. My Model name is Job. If the request to the API returns empty, I make another request, with only the field I want.

geocoded_by :full_address do |job, results|
    if results.empty?
      geo = Geocoder.search(job.city).first
      if geo.present?
        job.latitude = geo.latitude
        job.longitude = geo.longitude
      end
    else
      job.latitude = results.first.latitude
      job.longitude = results.first.longitude
    end
  end

  after_validation :geocode, if: ->(job) { job.will_save_change_to_address? || job.will_save_change_to_city? }