也许你用过这个rails geokit,在这个帖子里面对一些现有的ruby/rails geokit进行了对比。但是我要说的是,到现在为止,acts_as_geocodable 是最好的rails geokit。
acts_as_geocodable 的特点在于,不仅仅支持对于精确location 的查找,还在与能够支持对 locality 的查找。 关于 location 与 locality 的区别,请看这个文章。
demo:
比如说我创建了在 san francisco bay area 附近的几个parking garage 的位置:
>> l = Location.create :street => "123 Ofarrell St", :region => "CA", :postal_code => 94102, :locality => "San Francisco"
=> #<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">
>> l = Location.create :street => "500 Beach St", :region => "CA", :postal_code => 94133, :locality => "San Francisco"
=> #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">
只要我们保证location的输入是正确的,
我们就可以以各种方式来查找到这些位置,比如
>> Location.find(:all, :within => 100,
rigin => "San Francisco, ca")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>> Location.find(:all, :within => 100,
rigin => "San Francisco bay area")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>> Location.find(:all, :within => 100,
rigin => "bay area")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>> Location.find(:all, :within => 100,
rigin => "sf bay area")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>> Location.find(:all, :within => 100,
rigin => "silicon valley")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
按照zipcode来查找
>> Location.find(:all, :within => 100,
rigin => "94101")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
>> Location.find(:all, :within => 100,
rigin => "94108")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">]
我们创建一个位置的时候,只要保证street正确,可以不输入 zipcode, geocodable 会自动调用 google map 返回 zipcode
>> l = Location.create :street => "3 Embarcadero Ctr", :region => "CA", :locality => "San Francisco" (no zipcode)
=> #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">
>> Location.find(:all, :within => 100,
rigin => "silicon valley")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">, #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">]
比如说 University of California-Berkeley 离 bay area 和 Oakland 都比较近,那么都可以在这两个地方附近找到:
>> l = Location.create :street => "2921 Adeline St", :region => "CA", :locality => "Berkeley"
=> #<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">
>> Location.find(:all, :within => 30,
rigin => "bay area")
=> [#<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
>> Location.find(:all, :within => 10,
rigin => "oakland")
=> [#<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
最后有一点,silicon valley 和 bay area 在google maps 上的精确位置是不一样的,因此要限定范围的大小才能找到相应的目标。
>> Location.find(:all, :within => 10,
rigin => "San Francisco")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">, #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">, #<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
>> Location.find(:all, :within => 80,
rigin => "silicon valley")
=> []
>> Location.find(:all, :within => 90,
rigin => "silicon valley")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">, #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">, #<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
>> Location.find(:all, :within => 10,
rigin => "bay area")
=> []
>> Location.find(:all, :within => 30,
rigin => "bay area")
=> [#<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
>> Location.find(:all, :within => 40,
rigin => "bay area")
=> [#<Location id: 1, street: "123 Ofarrell St", locality: "San Francisco", region: "CA", postal_code: "94102", country: "US", created_at: "2008-11-26 12:33:06", updated_at: "2008-11-26 12:33:06">, #<Location id: 2, street: "500 Beach St", locality: "San Francisco", region: "CA", postal_code: "94133", country: "US", created_at: "2008-11-26 12:41:09", updated_at: "2008-11-26 12:41:09">, #<Location id: 3, street: "3 Embarcadero Center", locality: "San Francisco", region: "CA", postal_code: "94111", country: "US", created_at: "2008-11-26 13:13:54", updated_at: "2008-11-26 13:13:54">, #<Location id: 4, street: "2921 Adeline St", locality: "Berkeley", region: "CA", postal_code: "94703", country: "US", created_at: "2008-11-26 13:21:23", updated_at: "2008-11-26 13:21:23">]
geocodable 还有一点非常的好,就是它会把所有已经查询过的请求生成的结果放到数据库去,比如说执行
Location.find(:all, :within => 40,
rigin => "bay area")之后,就会把 bay area 的经纬度信息保存到 geocodes 这个表里面去,下一次再执行相同的查询的话,就直接从 geocodes 这个表获取 bay area的信息,而不需要再调用 google maps 的api 了。
还可以通过Location.find(:nearist, :within => 40,
rigin => 'bay area')来查找距离最近的位置。可以通过 Location.find(:all, within => 40,
rigin => 'bay area',
rder => 'distance') 来将查找结果按照距离排序。