Adding proximity filter to user search

544 views Asked by At

We have a user search set up on our application, so far just based on text content queries.

So here's what I have:

in models/user.rb

def self.search(query)
  where("description ilike ?", "%#{query}%")
end

in app/controllers/users_controller.rb

class UsersController < ApplicationController
  before_action :authorized?
  def index
    @users = User.all
    if params[:search]
      @users = User.search(params[:search]).order("created_at DESC")
    else
      @users = User.all.order('created_at DESC')
    end
  end

in views/index.html.erb

<%= form_tag(users_path, :method => "get", id: "search-form") do %>
  <%= text_field_tag :search, params[:search], placeholder: "Search Users" %>
  <%= submit_tag "Search", :name => nil %>
<% end %>

We're using rails and postgres. Geocoder gem is installed. We are storing current latitude and longitude in separate columns.

How would I add a proximity search filter, and what steps would I take in terms of MVC?

location is being stored in our scheme like this

 create_table "users", force: :cascade do |t|
    t.float    "latitude"
    t.float    "longitude"
2

There are 2 answers

0
Keyvman On BEST ANSWER

got it. I modified my index function on users controller to

if params[:search]
  @users = User.search(params[:search]) \
    .near([current_user.latitude, current_user.longitude], 10) \
    .order("created_at DESC")
end
7
Cody Caughlan On

Yeah the geocoder homepage doesnt have much info. I found more details in the actual README:

https://github.com/alexreisner/geocoder#readme

If you want to search by zip code you'll need to add a text field input to your form - lets call it zip_code. If you want a variable distance also add a select tag with numerical values representing the distance in miles, call this field distance.

Then server-side you need to convert the zip to latitude and longitude.

zip_result = Geocoder.search(params[:zip_code])
# Is an array of results, take the first one
if zip_result 
  result = zip_result.first
  lat = result.latitude
  lon = result.longitude

  # now we can search with our model: we are asking
  # Show me all Users within "distance_in_miles" of this geocoded
  # zip code
  distance_in_miles = params[:distance].to_i
  User.search(params[:query]).near([lat, lon], distance_in_miles)
end

This doesn't have any error checking or validation - its basically a proof of concept.