Commit b1dd748

mo khan <mo@mokhan.ca>
2016-05-01 19:47:49
return gyms located closest to a user.
1 parent 0b2c6bb
app/controllers/application_controller.rb
@@ -8,8 +8,12 @@ class ApplicationController < ActionController::Base
 
   protected
 
-  def current_user(session_id = session[:user_id])
-    @current_user ||= UserSession.authenticate(session_id).try(:user)
+  def current_session(session_id = session[:user_id])
+    @current_session ||= UserSession.authenticate(session_id)
+  end
+
+  def current_user
+    @current_user ||= current_session.try(:user)
   end
 
   def translate(key)
app/controllers/gyms_controller.rb
@@ -1,5 +1,5 @@
 class GymsController < ApplicationController
   def index
-    @gyms = Gym.closest_to(current_user)
+    @gyms = Gym.closest_to(current_session.location)
   end
 end
app/models/gym.rb
@@ -2,6 +2,13 @@ class Gym < ActiveRecord::Base
   validates_presence_of :name
   has_one :location, as: :locatable
   accepts_nested_attributes_for :location
+  acts_as_mappable through: :location
 
-  scope :closest_to, ->(user) { all }
+  scope :closest_to, ->(location) do
+    if location.present?
+      joins(:location).within(100, units: :kms, origin: location.coordinates)
+    else
+      all
+    end
+  end
 end
app/models/location.rb
@@ -1,5 +1,14 @@
 class Location < ActiveRecord::Base
+  belongs_to :locatable, polymorphic: true
   before_save :assign_coordinates
+  acts_as_mappable default_units: :kms,
+    distance_field_name: :distance,
+    lat_column_name: :latitude,
+    lng_column_name: :longitude
+
+  def coordinates
+    [latitude, longitude]
+  end
 
   class << self
     def build_from_ip(ip)
spec/models/gym_spec.rb
@@ -27,4 +27,21 @@ describe Gym do
       expect(subject.location.country).to eql('canada')
     end
   end
+
+  describe ".closest_to" do
+    let(:calgary) { create(:calgary) }
+    let(:edmonton) { create(:edmonton) }
+    let!(:calgary_gym) { create(:gym, location: calgary) }
+    let!(:edmonton_gym) { create(:gym, location: edmonton) }
+
+    it 'returns gyms near the location' do
+      results = Gym.closest_to(calgary)
+      expect(results).to match_array([calgary_gym])
+    end
+
+    it 'returns all the gyms' do
+      results = Gym.closest_to(nil)
+      expect(results).to match_array([calgary_gym, edmonton_gym])
+    end
+  end
 end
spec/support/http_authentication.rb
@@ -1,6 +1,7 @@
 module HttpAuthentication
-  def http_login(user)
+  def http_login(user, user_session = build(:user_session, id: SecureRandom.uuid, user: user))
     allow(controller).to receive(:current_user).and_return(user)
-    session[:user_id] = build(:user_session, id: SecureRandom.uuid, user: user).id
+    allow(controller).to receive(:current_session).and_return(user_session)
+    session[:user_id] = user_session.id
   end
 end
spec/factories.rb
@@ -73,5 +73,19 @@ FactoryGirl.define do
     region { FFaker::AddressCA.province }
     postal_code { FFaker::AddressCA.postal_code }
     country { FFaker::Address.country }
+    factory :calgary do
+      latitude { 51.0130333 }
+      longitude { -114.2142365 }
+      city { "Calgary" }
+      region { "AB" }
+      country { "CA" }
+    end
+    factory :edmonton do
+      latitude { 53.5557956 }
+      longitude { -113.6340292 }
+      city { "Edmonton" }
+      region { "AB" }
+      country { "CA" }
+    end
   end
 end
Gemfile
@@ -23,6 +23,7 @@ source 'https://rubygems.org' do
   gem 'foreman', group: :development
   gem 'foundation-rails', '~> 5.5'
   gem 'geocoder'
+  gem 'geokit-rails'
   gem 'griddler'
   gem 'griddler-mandrill'
   gem 'groupdate'
Gemfile.lock
@@ -159,6 +159,10 @@ GEM
       railties (>= 3.1.0)
       sass (>= 3.3.0, < 3.5)
     geocoder (1.3.4)
+    geokit (1.10.0)
+    geokit-rails (2.1.0)
+      geokit (~> 1.5)
+      rails (>= 3.0)
     gherkin (3.2.0)
     git-version-bump (0.15.1)
     globalid (0.3.6)
@@ -422,6 +426,7 @@ DEPENDENCIES
   foreman!
   foundation-rails (~> 5.5)!
   geocoder!
+  geokit-rails!
   griddler!
   griddler-mandrill!
   groupdate!