geokit / geokit-rails

Official Geokit plugin for Rails/ActiveRecord. Provides location-based goodness for your Rails app. Requires the Geokit gem.
MIT License
1.57k stars 245 forks source link

distance_by method is not working correctly #125

Open pblogs opened 7 years ago

pblogs commented 7 years ago

So, I'm using geokit-rails and I would like to sort by distance, specifically showing the nearest meals first and descending from there. e.g. 5km, 10km, 15km.

However, for some reason the distance_by method isn't working at all, and the distances are all over the place.

This is how we're using it:

all_venues = Venue.where( 'listed = ? AND packages_count > ?', true, 0 ).by_distance(origin: search_location).search(params[:search]) || Venue.where(listed: true).all

Are there any work around methods to use? Or how can I sort from nearest to furthest with geokit-rails?

Thanks!

locolab commented 7 years ago

+1

mnoack commented 7 years ago

@pblogs @locolab - Whilst I don't have the time to resolve this issue, I'm more than able to review a PR which resolves the issue (along with a test of the currently failing case).

I'm sure with a little debugging (debugger, binding.pry) you'll be able to discover where the code is going wrong.

pezholio commented 7 years ago

Can confirm this is an issue for me as well. The SQL that is generated in for my use case (in postgres) is:

Place.by_distance(origin: [51.672607, 0.651835]).to_sql
#=> SELECT "places".* FROM "places" WHERE (places.latitude IS NOT NULL AND places.longitude IS NOT NULL)  ORDER BY "places"."name" ASC, (ACOS(least(1,COS(0.9018571252390695)*COS(0.01137666692973724)*COS(RADIANS(places.latitude))*COS(RADIANS(places.longitude))+        COS(0.9018571252390695)*SIN(0.01137666692973724)*COS(RADIANS(places.latitude))*SIN(RADIANS(places.longitude))+        SIN(0.9018571252390695)*SIN(RADIANS(places.latitude))))*3963.1899999999996)         ASC

Looking under the hood, Postgres ignores the distance based ordering. If I add it to the select query as a virtual column, like so:

SELECT "places".*, (ACOS(least(1,COS(0.9018571252390695)*COS(0.01137666692973724)*COS(RADIANS(places.latitude))*COS(RADIANS(places.longitude))+        COS(0.9018571252390695)*SIN(0.01137666692973724)*COS(RADIANS(places.latitude))*SIN(RADIANS(places.longitude))+        SIN(0.9018571252390695)*SIN(RADIANS(places.latitude))))*3963.1899999999996) AS distance FROM "places" WHERE (places.latitude IS NOT NULL AND places.longitude IS NOT NULL) ORDER BY distance

I get the expected result. I'm using Postgres 9.6.5 and Rails 4.2 BTW.