Vasco
Vasco

Reputation: 361

Using Ruby Geocoder for retrieving nearby users and return distance

Is it possible to use Geocoder for retrieving, say, nearby users within a certain radius, and make it return the result of the distance calculation without having to repeat for display?

For example, say we use this (in a Rails application):

User.near(@me, 10, units: :km)

It will return an ActiveRecord::Relation with all the users that are within 10 kilometres of user @me.

If I now want to display a list with all the returned users and their distance to @me, do I need to actually recompute the distances one by one using distance_to, or is there are a way to make Geocoder return the computed distances in an added model attribute (for example)?

Upvotes: 2

Views: 869

Answers (2)

Elvn
Elvn

Reputation: 3057

I'm using this embedded Ruby version of the logic, which is similar logically to the answer given by @maxcal above. I'm including it because the trace below relates to this code.

<% for location in @location.nearbys(20) %>
  <li> <span class="badge"><%= location.distance.round(2) %> miles</span> from here you'll find <strong>
  <%= link_to location.name, location %> </strong> at <%= location.full_address %>.</li>
<% end %> 

But, I think the answer is that Geocoder is creating a temp data store for the set of conforming records. .distance is the key variable.

If I look at the trace, it shows the initial database hits, but no subsequent hits for each item in the loop. One could look at the Geocoder code and confirm, but the trace seems to be conclusive.

  [1m[36m (0.0ms)[0m  [1mSELECT COUNT(*) FROM "reviews" WHERE "reviews"."user_id" = $1[0m  [["user_id", 8]]
  Rendered shared/_user_posted_badge.html.erb (15.6ms)
// Comment Geocoding starts here
  Rendered locations/_map_show.html.erb (0.0ms)
  [1m[35mLocation Load (0.0ms)[0m  SELECT locations.*, 3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((30.267153 - locations.latitude) * PI() / 180 / 2), 2) + COS(30.267153 * PI() / 180) * COS(locations.latitude * PI() / 180) * POWER(SIN((-97.7430608 - locations.longitude) * PI() / 180 / 2), 2))) AS distance, MOD(CAST((ATAN2( ((locations.longitude - -97.7430608) / 57.2957795), ((locations.latitude - 30.267153) / 57.2957795)) * 57.2957795) + 360 AS decimal), 360) AS bearing FROM "locations" WHERE (locations.latitude BETWEEN 29.977689433778306 AND 30.556616566221695 AND locations.longitude BETWEEN -98.07821040202988 AND -97.40791119797011 AND (3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((30.267153 - locations.latitude) * PI() / 180 / 2), 2) + COS(30.267153 * PI() / 180) * COS(locations.latitude * PI() / 180) * POWER(SIN((-97.7430608 - locations.longitude) * PI() / 180 / 2), 2)))) BETWEEN 0.0 AND 20 AND locations.id != 65)  ORDER BY distance ASC
// Geocoding section complete
  [1m[36mPhotograph Exists (0.0ms)[0m  [1mSELECT  1 AS one FROM "photographs" WHERE "photographs"."location_id" = $1 LIMIT 1[0m  [["location_id", 65]]
  [1m[35mPhotograph Load (0.0ms)[0m  SELECT "photographs".* FROM "photographs" WHERE "photographs"."location_id" = $1  ORDER BY "photographs"."created_at" DESC  [["location_id", 65]]

Upvotes: 1

max
max

Reputation: 101811

When you run a location-aware query the returned objects have two attributes added to them:

User.near(@me, 10, units: :km).each do |user|
  puts "#{user.name} is #{user.distance} clicks to the #{user.bearing}"
end

Upvotes: 1

Related Questions