<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>John Yerhot - Weblog &#187; Ruby On</title>
	<atom:link href="http://www.johnyerhot.com/tag/ruby-on/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.johnyerhot.com</link>
	<description>im in ur computrz makin castz</description>
	<lastBuildDate>Tue, 29 Jun 2010 04:32:50 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Zip Code Distance Searching in Ruby on Rails</title>
		<link>http://www.johnyerhot.com/2009/06/23/zipcode-distance-searching-in-ruby-on-rails/</link>
		<comments>http://www.johnyerhot.com/2009/06/23/zipcode-distance-searching-in-ruby-on-rails/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 01:51:59 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby On Rails]]></category>
		<category><![CDATA[Geocoding]]></category>
		<category><![CDATA[Ruby On]]></category>

		<guid isPermaLink="false">http://www.johnyerhot.com/?p=105</guid>
		<description><![CDATA[In my last entry we looked at using scopes to dynamically build scopes for searching in your Ruby on Rails application.  In Tryst, we needed to let our uses search for other singles that were xxx miles from their location.  We require that new users enter their zip code, so that is what we had [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://www.johnyerhot.com/2009/06/21/smart-searching-using-named-scopes/">last entry</a> we looked at using scopes to dynamically build scopes for searching in your Ruby on Rails application.  In <a href="http://trystme.com">Tryst</a>, we needed to let our uses search for other singles that were xxx miles from their location.  We require that new users enter their zip code, so that is what we had to go off of.</p>
<p>When I was researching the best way to do this, I did a quick Twitter poll &#8211; most of my friend thought I should just use <a href="http://code.google.com/apis/maps/documentation/services.html">Google&#8217;s GeoCoding API</a>, which will let you preform these types of searches.  I really didn&#8217;t want to go this route for a couple reasons.</p>
<ol>
<li>It&#8217;s an external dependency.  Yes, Google&#8217;s uptime is impeccable, but I don&#8217;t want to rely on them</li>
<li>Google&#8217;s TOS requires that the site/app/service be free.  Tryst may end up with paid features down the road and I didn&#8217;t want to have to rewrite a substantial amount of code 1 year from now.</li>
<li>It&#8217;s a challenge.</li>
</ol>
<p>So, we decided to do our own thing.</p>
<p>Our workflow for a search would work like this &#8211; we get a distance and a zip code as search parameters, feed both of these into something that returns all the zip codes within the specified distance, and then find all the uses in those zip codes.  Easy enough.</p>
<p>PS.  I&#8217;m using MySQL here.</p>
<p>First, we need a reference for zip codes.  I found <a href="http://www.maxmind.com/app/geolitecity">this</a> great free CSV that has all zip codes, major cities, longitude, latitude, area codes, and even <a href="http://code.google.com/apis/adwords/docs/developer/adwords_api_us_metros.html">metropolitan codes</a>. Import it into your database and remove any rows that were not in the US.  I actually had a &#8216;Location&#8217; model in my Rails application that I imported this into.</p>
<p>After some digging around the webs, I found some crazy algorithms for generating distance between different locations based on their longitude and latitude.  I&#8217;m not going to pretend to understand everything that is happening here, but after some playing around I ended up with this:</p>
<pre>SELECT o.zip_code
FROM locations z, locations o, locations a

WHERE z.zip_code = #{zip_code}
AND	z.zip_code = a.zip_code
AND	(3956 * (2 * ASIN(SQRT(
		POWER(SIN(((z.latitude-o.latitude)*0.017453293)/2),2) +
		COS(z.latitude*0.017453293) *
		COS(o.latitude*0.017453293) *
		POWER(SIN(((z.longitude-o.longitude)*0.017453293)/2),2)
	)))) &lt;= #{distance}</pre>
<p>I&#8217;ll let you guess which part does the calculation. :)<br />
<strong>zip_code</strong> and <strong>distance</strong> you&#8217;ll need to pipe into the SQL, but you&#8217;ll get back all the zip codes with in your specification.  We just thew the returned array of zip odes into a scope like this:</p>
<pre># models/users.rb
def search(params)
    scope = User.scoped({})
    ...
    scope = scope.conditions "users.zip_code in (?)", zip_codes unless zip_codes.blank?
    ...
end</pre>
<p>Now, this query is fairly slow.  By slow, I mean about 25-30ms correctly indexed on my development box.  For us it&#8217;s just fine.</p>
<p>I hope that helped someone out &#8211; I had a hell of a time finding a solution I liked and I really think this is the best one.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.johnyerhot.com/2009/06/23/zipcode-distance-searching-in-ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
