-
-
Save santoshbt/2282421 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace :load do | |
ZIP_CODE_DATA_URL = 'http://www.census.gov/tiger/tms/gazetteer/zips.txt' | |
# Swiped from ActiveRecord migrations.rb | |
def announce(message) | |
length = [0, 75 - message.length].max | |
puts "== %s %s" % [message, "=" * length] | |
end | |
desc "Loads zip codes from #{ZIP_CODE_DATA_URL}" | |
task :zip_codes => :environment do | |
begin | |
time = Benchmark.measure do | |
require 'fastercsv' | |
require 'open-uri' | |
FasterCSV.parse(open(ZIP_CODE_DATA_URL).read) do |row| | |
# Connascence of Position, Jim Weirich forgive me! | |
zip = Zip.create!( | |
:code => row[1], | |
:state => row[2], | |
:city => row[3], | |
:lat => row[4], | |
:lon => row[5]) | |
puts "%20s, %2s, %5s" % [zip.city, zip.state, zip.code] | |
end | |
end | |
announce "Loaded %5d zip codes in (%2dm %2.0fs)" % [Zip.count, *time.real.divmod(60)] | |
rescue LoadError | |
puts "This rake task requires fastercsv. To install, run this command:\n\n sudo gem install fastercsv\n\n" | |
end | |
end | |
desc "Creates n number random users using the Random Data gem, defaults to 1000" | |
task :random_users, :n, :needs => :environment do |t, args| | |
begin | |
n = args.n.to_i < 1 ? 1000 : args.n.to_i | |
time = Benchmark.measure do | |
require 'random_data' | |
domains = %w[yahoo.com gmail.com privacy.net webmail.com msn.com hotmail.com example.com privacy.net] | |
zips = Zip.all #Can we fit 29k zip codes into memory? | |
n.times do |i| | |
user = User.new(:first_name => Random.firstname, :last_name => Random.lastname) | |
user.username = "#{user.first_name[0,1]}#{user.last_name}#{i}".downcase | |
user.password = user.password_confirmation = "secret" | |
user.email = "#{user.username}\@#{domains.rand}" | |
user.address = Random.address_line_1 | |
zip = zips.rand | |
user.city = zip.city.titleize | |
user.state = zip.state | |
user.zip = zip | |
user.save! | |
puts "%6d: %15s %15s, %30s, %20s, %2s, %5s" % [(i+1), user.first_name, user.last_name, user.email, user.city, user.state, user.zip.code] | |
end | |
end | |
announce "Loaded %6d users in (%2dm %2.0fs)" % [n, *time.real.divmod(60)] | |
rescue LoadError | |
puts "This rake task requires random_data. To install, run this command:\n\n sudo gem install random_data\n\n" | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User < ActiveRecord::Base | |
belongs_to :zip | |
named_scope :within_miles_of_zip, lambda{|radius, zip| | |
# Get the parameters for the search | |
area = zip.area_for(radius) | |
# now find all zip codes that are within | |
# these min/max lat/lon bounds and return them | |
# weed out any zip codes that fall outside of the search radius | |
{ :select => "#{User.columns.map{|c| "users.#{c.name}"}.join(', ')}, sqrt( | |
pow(#{area[:lat_miles]} * (zips.lat - #{zip.lat}),2) + | |
pow(#{area[:lon_miles]} * (zips.lon - #{zip.lon}),2)) as distance", | |
:joins => :zip, | |
:conditions => "(zips.lat BETWEEN #{area[:min_lat]} AND #{area[:max_lat]}) | |
AND (zips.lon BETWEEN #{area[:min_lon]} AND #{area[:max_lon]}) | |
AND sqrt(pow(#{area[:lat_miles]} * (zips.lat - #{zip.lat}),2) + | |
pow(#{area[:lon_miles]} * (zips.lon - #{zip.lon}),2)) <= #{area[:radius]}", | |
:order => "distance"} | |
} | |
def within_miles(radius) | |
self.class.within_miles_of_zip(radius, zip) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Zip < ActiveRecord::Base | |
has_many :users | |
def self.code(code) | |
first(:conditions => {:code => code}) | |
end | |
# Returns a hash with values that can be used | |
# to perform a proximity search query | |
def area_for(radius) | |
area = {} | |
area[:radius] = radius.to_f | |
area[:lat_miles] = 69.172 #this is constant | |
#longitude miles varies based on latitude, that is calculated here | |
area[:lon_miles] = (area[:lat_miles] * Math.cos(lat * (Math::PI/180))).abs | |
area[:lat_degrees] = radius/area[:lat_miles] #radius in degrees latitude | |
area[:lon_degrees] = radius/area[:lon_miles] #radius in degrees longitude | |
#now set min and max lat and long accordingly | |
area[:min_lat] = lat - area[:lat_degrees] | |
area[:max_lat] = lat + area[:lat_degrees] | |
area[:min_lon] = lon - area[:lon_degrees] | |
area[:max_lon] = lon + area[:lon_degrees] | |
area | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment