Gets objects within the specified range from a certain point and sorts the objects in order of closeness.
Use geokit-rails as a location-related gem. I think there are various other gems, but I will use this for personal reasons. The setup is written on github, so it is omitted. https://github.com/geokit/geokit-rails
The model after setup looks like this.
user.rb
class User < ApplicationRecord
acts_as_mappable default_units: :kms, default_formula: :sphere
end
First, get an object that exists within a radius of n kilometers from a certain point. Here, Tokyo Tower is represented by latitude and longitude, and 5km is specified from there.
users_controller.rb
def index
users = User.within(5, origin: [35.658694, 139.745390])
end
This will calculate the distance from the lat, lng columns (by default) and retrieve the object.
In the README
You can add order clauses in the chain as for any ActiveRecord query Location.within(5, :origin => @somewhere).order('nbr_seats ASC') You can even sort by distance (use the same name as specified in the model class) Location.within(5, :origin => @somewhere).order('distance DESC, nbr_seats ASC')
Because it is written, when I try it
$ rails c --sandbox
> users = User.within(5, origin: [35.658694, 139.745390]).order('distance DESC, nbr_seats ASC')
I got the following error.
ActiveRecord::StatementInvalid (Mysql2::Error: Unknown column 'distance' in 'order clause')
Looking at the issue, it seems that the distance field has been removed. https://github.com/geokit/geokit-rails/issues/39 https://github.com/geokit/geokit-rails/issues/56 However, since it is old information, I'm sorry if it is different now.
In the README
The plug-in creates a calculated distance field on AR instances that have been retrieved through a Geokit location query. By default, these fields are known as "distance" but this can be changed through the :distance_field_name key.
I would be grateful if you could tell me if it is different.
However, I couldn't do it in my environment, so I will proceed by saying that I can't.
First, it is necessary to hold the distance from the specified location (Tokyo Tower in this case) as a state for each of the extracted objects, but since I thought that it was not necessary to hold it in the column, I modeled the virtual (?) Attribute. I will give it to you. Here, it is distance.
user.rb
attr_accessor :distance
#abridgement
Next, we need to find the distance to put in: distance. This can be achieved with the geokit-rails distance_from method.
$ rails c --sandbox
> user = User.first
> user.distance_from([35.658694, 139.745390])
>The distance to that user is the return value.
In order to actually put this obtained distance temporarily in: distance, define an instance method.
user.rb
def get_distance(lat, lng)
self.distance = distance_from([lat, lng])
end
#abridgement
Each object can now keep a distance from the specified point. Add each syntax to the controller.
users_controller.rb
def index
users = User.within(5, origin: [35.658694, 139.745390])
get_distance_users = users.each {|user| user.get_distance(35.658694, 139.745390)}
end
However, this has not been sorted yet. This is done using ruby's sort_by method.
users_controller.rb
def index
users = User.within(5, origin: [35.658694, 139.745390])
get_distance_users = users.each {|user| user.get_distance(35.658694, 139.745390)}
sorted_users = get_distance_users.sort_by {|a| a.distance}
end
You now have an array of objects sorted in ascending order based on: distance in sorted_users.
Recommended Posts