LearningRoR
LearningRoR

Reputation: 27192

Searching with Geocoder and Sunspot?

I'm using the Geocoder and Sunspot gem in my application and I have a field called :search_near_address that is suppose to give users the ability to input an address they want to search near within X amount of miles. What I am trying to map to is my Stores :address to use for the :search_near_address field. This way users can input an address ( i.e. 451 University Avenue, Palo Alto, CA ) in the :search_near_address field and it will search in a radius of 50 miles.

Answer

Sunspot 1.2.1


class Store < ActiveRecord::Base
   attr_accessible :address, :latitude, :longitude
   has_many :products
   geocoded_by :address
   after_validation :geocode
   reverse_geocoded_by :latitude, :longitude
   after_validation :reverse_geocode      
end

class Product < ActiveRecord::Base
   belongs_to :store

   searchable do # Searching with product model.
     string :search_near # For rake sunspot:reindex
     location :location
   end

   def search_near_address
 store.address if store # You may have to use the "if store".
   end

   def location
    # may need the "if store" after longitude)....
Sunspot::Util::Coordinates.new(store.latitude, store.longitude)
   end
end

class SearchController < ApplicationController

  def index
    @search = Product.search do |q| # Search with sunspot
      q.fulltext params[:search]
      q.with(:location).near(*Geocoder.coordinates(params[:search_near_address]), :precision => 4) if params[:search_near_address].present?
    end 
    @products = @search.results # Return results from Product.search block.
  end
end

# search/index/html.erb
<%= form_tag results_search_index_path, :method => 'get' do %>
    <%= text_field_tag :search, params[:search] %>
    <%= text_field_tag :search_near_address, params[:search_near_address] %>
    <%= submit_tag "Go", :name => nil %>
<% end %>

Upvotes: 2

Views: 2165

Answers (2)

brutuscat
brutuscat

Reputation: 3130

First what @m_x said is right, you can't expect assigning the Store#near results to the @search object would work....

Just reading the docs about Geospatial in https://github.com/sunspot/sunspot, you can clearly see that you are missing a few things:

You have to declare your Geospatial field using the latitude and longitude fields that geocoder requires:

class Product < ActiveRecord::Base
   belongs_to :store

   searchable do # for Sunspot search.
     string :search_near
     latlon(:location) { 
       Sunspot::Util::Coordinates.new(category.latitude, category.longitude)
     }
   end

   def search_near
     #I changed this because business_store will not work out.
     store.address
   end
end

Then you can search (after having indexed something) like this:

class SearchController < ApplicationController

  def index
    # Search with sunspot
    @search = Sunspot.search(Product) do
      fulltext params[:search]

      # The "*" pop off the elements of the array that 
      # Geocoder.coordinates returns.
      with(:location).near(*Geocoder.coordinates(params[:search_near]), 
                           :precision => 6)

      # NOTE: You could also use the in_radius method but only in the pre-release version:
      # with(:location).in_radius(*Geocoder.coordinates(params[:search_near]), 100) if params[:search_near].present?
    end

    # Return results from Product.search block.
    @products = @search.results 
  end
end

Also read about the :precision option here http://sunspot.github.com/docs/Sunspot/DSL/RestrictionWithNear.html#near-instance_method

About Geocoder https://github.com/alexreisner/geocoder

Upvotes: 7

Paul Carey
Paul Carey

Reputation: 566

Not sure I fully understand what it is your attempting with the above but I have a similar situation in trying to get geocoder and sunspot to play together.

This is untested as yet but this is my current thinking....

Event.search do
      keywords  search_terms
      any_of do
        with(:id).any_of(Event.near(coordinates,50).map(&:id))
      end
end.results

Essentially I'm trying to combine the two result sets to only bring back the results that match both the distance and keyword terms.

Hope this is of help to someone at least.

Upvotes: 3

Related Questions