add geolocation search for public channels
This commit is contained in:
parent
6d2d9f2b17
commit
2125d714e6
1
Gemfile
1
Gemfile
@ -35,6 +35,7 @@ gem 'em-http-request'
|
|||||||
gem 'tzinfo'
|
gem 'tzinfo'
|
||||||
gem 'tzinfo-data'
|
gem 'tzinfo-data'
|
||||||
gem 'turbolinks'
|
gem 'turbolinks'
|
||||||
|
gem 'geokit-rails'
|
||||||
|
|
||||||
# to use debugger
|
# to use debugger
|
||||||
# gem 'ruby-debug'
|
# gem 'ruby-debug'
|
||||||
|
@ -144,6 +144,9 @@ GEM
|
|||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
geokit (1.8.4)
|
geokit (1.8.4)
|
||||||
multi_json (>= 1.3.2)
|
multi_json (>= 1.3.2)
|
||||||
|
geokit-rails (2.0.1)
|
||||||
|
geokit (~> 1.5)
|
||||||
|
rails (>= 3.0)
|
||||||
gravatarify (3.1.0)
|
gravatarify (3.1.0)
|
||||||
has_scope (0.6.0.rc)
|
has_scope (0.6.0.rc)
|
||||||
actionpack (>= 3.2, < 5)
|
actionpack (>= 3.2, < 5)
|
||||||
@ -362,6 +365,7 @@ DEPENDENCIES
|
|||||||
factory_girl_rails
|
factory_girl_rails
|
||||||
faker
|
faker
|
||||||
geokit
|
geokit
|
||||||
|
geokit-rails
|
||||||
gravatarify
|
gravatarify
|
||||||
i18n-tasks (~> 0.5.4)
|
i18n-tasks (~> 0.5.4)
|
||||||
jquery-rails (= 3.0.4)
|
jquery-rails (= 3.0.4)
|
||||||
|
@ -6,6 +6,7 @@ class ChannelsController < ApplicationController
|
|||||||
layout 'application', :except => [:social_show, :social_feed]
|
layout 'application', :except => [:social_show, :social_feed]
|
||||||
protect_from_forgery :except => [:realtime, :realtime_update, :post_data, :create, :destroy, :clear]
|
protect_from_forgery :except => [:realtime, :realtime_update, :post_data, :create, :destroy, :clear]
|
||||||
require 'csv'
|
require 'csv'
|
||||||
|
require 'will_paginate/array'
|
||||||
|
|
||||||
# get list of all realtime channels
|
# get list of all realtime channels
|
||||||
def realtime
|
def realtime
|
||||||
@ -55,6 +56,10 @@ class ChannelsController < ApplicationController
|
|||||||
elsif params[:tag].present?
|
elsif params[:tag].present?
|
||||||
@header = "#{t(:tag).capitalize}: #{params[:tag]}"
|
@header = "#{t(:tag).capitalize}: #{params[:tag]}"
|
||||||
@channels = Channel.public_viewable.active.order('ranking desc, updated_at DESC').with_tag(params[:tag]).paginate :page => params[:page]
|
@channels = Channel.public_viewable.active.order('ranking desc, updated_at DESC').with_tag(params[:tag]).paginate :page => params[:page]
|
||||||
|
# get channels by location
|
||||||
|
elsif params[:latitude].present? && params[:longitude].present? && params[:distance].present?
|
||||||
|
@header = "#{t(:channels_near)}: [#{params[:latitude]}, #{params[:longitude]}]"
|
||||||
|
@channels = Channel.location_search(params).paginate :page => params[:page]
|
||||||
# normal channel list
|
# normal channel list
|
||||||
else
|
else
|
||||||
@header = t(:featured_channels)
|
@header = t(:featured_channels)
|
||||||
|
@ -52,6 +52,11 @@
|
|||||||
|
|
||||||
class Channel < ActiveRecord::Base
|
class Channel < ActiveRecord::Base
|
||||||
include KeyUtilities
|
include KeyUtilities
|
||||||
|
# geolocation search: Channel.within(miles, :origin => [latitude, longitude]).to_a
|
||||||
|
# example: channels = Channel.within(4000, :origin => [4, 6]).to_a
|
||||||
|
# channels.sort_by{|s| s.distance_to([4, 6])}
|
||||||
|
acts_as_mappable :default_units => :kms, :default_formula => :sphere,
|
||||||
|
:distance_field_name => :distance, :lat_column_name => :latitude, :lng_column_name => :longitude
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
has_many :feeds
|
has_many :feeds
|
||||||
@ -85,6 +90,18 @@ class Channel < ActiveRecord::Base
|
|||||||
cattr_reader :per_page
|
cattr_reader :per_page
|
||||||
@@per_page = 15
|
@@per_page = 15
|
||||||
|
|
||||||
|
# search for public channels within a certain distance from the origin
|
||||||
|
# requires latitude, longitude, and distance to be present as options keys
|
||||||
|
# distance is in kilometers
|
||||||
|
def self.location_search(options = {})
|
||||||
|
# set the origin
|
||||||
|
origin = [options[:latitude].to_f, options[:longitude].to_f]
|
||||||
|
# query the database
|
||||||
|
channels = Channel.public_viewable.within(options[:distance].to_f, :origin => origin)
|
||||||
|
# sort channels by distance
|
||||||
|
return channels.sort_by{|c| c.distance_to(origin)}
|
||||||
|
end
|
||||||
|
|
||||||
# how often the channel is updated
|
# how often the channel is updated
|
||||||
def update_rate
|
def update_rate
|
||||||
last_feeds = self.feeds.order('entry_id desc').limit(2)
|
last_feeds = self.feeds.order('entry_id desc').limit(2)
|
||||||
|
@ -16,6 +16,14 @@ Valid parameters:
|
|||||||
<li><b>username</b> (string) Person's username that you want to search Channels for (optional)</li>
|
<li><b>username</b> (string) Person's username that you want to search Channels for (optional)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
You can also search for Channels within a certain distance of a location by including the following location parameters:
|
||||||
|
<ul>
|
||||||
|
<li><b>latitude</b> (decimal) - Latitude of location in degrees. (optional)</li>
|
||||||
|
<li><b>longitude</b> (decimal) - Longitude of location in degrees. (optional)</li>
|
||||||
|
<li><b>distance</b> (decimal) - Distance in kilometers from location. (optional)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
Example GET:
|
Example GET:
|
||||||
|
|
||||||
@ -163,6 +171,7 @@ Valid parameters:
|
|||||||
<li><b>api_key</b> (string) - Your Account API Key (this is different from a Channel API Key, and can be found in your Account settings). (required)</li>
|
<li><b>api_key</b> (string) - Your Account API Key (this is different from a Channel API Key, and can be found in your Account settings). (required)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
Example GET:
|
Example GET:
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ en:
|
|||||||
channel_url: "URL"
|
channel_url: "URL"
|
||||||
channels: "Channels"
|
channels: "Channels"
|
||||||
channels_my: "My Channels"
|
channels_my: "My Channels"
|
||||||
|
channels_near: "Channels Near"
|
||||||
channels_public: "Public Channels"
|
channels_public: "Public Channels"
|
||||||
channels_public_view: "View Public Channels"
|
channels_public_view: "View Public Channels"
|
||||||
channel_video_type_blank: "Either Youtube, or Vimeo, is required if a Video ID is specified."
|
channel_video_type_blank: "Either Youtube, or Vimeo, is required if a Video ID is specified."
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
class AddGeolocationIndexToChannels < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_index :channels, [:latitude, :longitude]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20140801191621) do
|
ActiveRecord::Schema.define(version: 20140804223739) do
|
||||||
|
|
||||||
create_table "active_admin_comments", force: true do |t|
|
create_table "active_admin_comments", force: true do |t|
|
||||||
t.string "namespace"
|
t.string "namespace"
|
||||||
@ -107,6 +107,7 @@ ActiveRecord::Schema.define(version: 20140801191621) do
|
|||||||
t.text "metadata"
|
t.text "metadata"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_index "channels", ["latitude", "longitude"], name: "index_channels_on_latitude_and_longitude", using: :btree
|
||||||
add_index "channels", ["public_flag", "last_entry_id", "updated_at"], name: "channels_public_viewable", using: :btree
|
add_index "channels", ["public_flag", "last_entry_id", "updated_at"], name: "channels_public_viewable", using: :btree
|
||||||
add_index "channels", ["ranking", "updated_at"], name: "index_channels_on_ranking_and_updated_at", using: :btree
|
add_index "channels", ["ranking", "updated_at"], name: "index_channels_on_ranking_and_updated_at", using: :btree
|
||||||
add_index "channels", ["realtime_io_serial_number"], name: "index_channels_on_realtime_io_serial_number", using: :btree
|
add_index "channels", ["realtime_io_serial_number"], name: "index_channels_on_realtime_io_serial_number", using: :btree
|
||||||
|
@ -125,6 +125,13 @@ describe ChannelsController do
|
|||||||
get :index, {:api_key => @user.api_key, :format => 'json'}
|
get :index, {:api_key => @user.api_key, :format => 'json'}
|
||||||
response.should be_successful
|
response.should be_successful
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "searches nearby public channels" do
|
||||||
|
channel1 = Channel.create(name: 'channel1', latitude: 10, longitude: 10, public_flag: true)
|
||||||
|
channel2 = Channel.create(name: 'channel2', latitude: 60, longitude: 60, public_flag: true)
|
||||||
|
get :public, {api_key: @user.api_key, latitude: 59.8, longitude: 60.2, distance: 100, format: 'json'}
|
||||||
|
JSON.parse(response.body)['channels'][0]['name'].should eq("channel2")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "create channel" do
|
describe "create channel" do
|
||||||
|
@ -134,5 +134,17 @@ describe Channel do
|
|||||||
channels.count.should == 1
|
channels.count.should == 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'geolocation' do
|
||||||
|
it 'should find nearby channels' do
|
||||||
|
channel1 = Channel.create(latitude: 10, longitude: 10, public_flag: true)
|
||||||
|
channel2 = Channel.create(latitude: 60, longitude: 60, public_flag: true)
|
||||||
|
channel3 = Channel.create(latitude: 60, longitude: 60, public_flag: false)
|
||||||
|
Channel.location_search({latitude: 9.8, longitude: 10.2, distance: 100}).first.should eq(channel1)
|
||||||
|
Channel.location_search({latitude: 60.2, longitude: 59.8, distance: 100}).first.should eq(channel2)
|
||||||
|
Channel.location_search({latitude: 60.2, longitude: 59.8, distance: 100}).count.should eq(1)
|
||||||
|
Channel.location_search({latitude: 30.8, longitude: 30.2, distance: 100}).count.should eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user