Geocoder - A complete geocoding solution for Ruby
This post hasn't been updated for 3 years
Geocoder
Geocoder là một giải pháp mã hóa địa lý hoàn chỉnh cho Ruby. Nó cho phép chuyển đổi tên các địa điểm thành tọa độ địa lý và ngược lại, thậm chí có thể chuyển đổi địa chỉ IP thành các địa chỉ đường phố. Nó cũng cho phép bạn tìm kiếm những địa điểm gần đó với khoảng cách và chỉ dẫn và rất nhiều tính năng hữu ích khác.
Khả năng tương thích
- Hỗ trợ nhiều bản Ruby: Ruby 1.9.3, 2.x, JRuby, and Rubinius.
- Hỗ trợ nhiều database: MySQL, PostgreSQL, SQLite, and MongoDB (1.7.0 and cao hơn).
- Hỗ trợ Rails 3, 4 và 5. Nếu bạn cần sử dụng với Rails 2, hãy xem rails2 branch (không còn maintained và bị giới hạn tính năng)
- Làm việc rất tốt bên ngoài Rails, bạn chỉ cần cài đặt
json
(cho MRI) vàjson_pure
(cho JRuby) gem
Cài đặt
Chạy lệnh sau trong terminal
gem install geocoder
hoặc thêm gem sau vào Gemfile
:
gem 'geocoder'
rồi chạy lệnh bundle install
Demo
Sau đây, tôi sẽ tạo một ví dụ để các bạn hiểu rõ hơn về các tính năng của Geocoder
nhé.
Đầu tiên, tạo cho mình một ứng dụng Rails:
rails new GeocoderTest -T
Tiếp theo, tạo một Location
model với scaffold bao gồm các trường address
, latitude
và longitude
.
rails g scaffold Location address:string latitude:float longitude:float
Các trường latitude
và longitude
, Geocoder sẽ sử dụng để lưu trữ tọa độ của địa điểm. Đừng quên migrate database của bạn để tạo bảng locations
mới nhé: rake db:migrate
Bây giờ chúng ta đã có thể tạo một địa điểm mới như sau
Tiếp theo, chúng ta sẽ sửa đổi Location
model một chút, thêm một geocoded_by
vào một thuộc tính mà chúng ta muốn Geocoder
chuyển đổi geocoding, trong trường hợp này là trường address
.
#/app/models/location.rb
class Location < ActiveRecord::Base
geocoded_by :address
end
Khi một địa điểm được tạo hoặc được cập nhật, chúng ta cần phải gọi phương thức geocode
để thực hiện việc mã hóa địa chỉ (geocoding
). Mọi người thường phải sử dụng một after_validation
callback để làm được điều này.
#/app/models/location.rb
class Location < ActiveRecord::Base
geocoded_by :address
after_validation :geocode
end
Phương thức Geocode
sẽ gửi một request đến một API bên ngoài, mặc định là Google Maps API.
Chúng ta có thể khởi động ứng dụng bây giờ và thử Geocoder xem. Khi chúng ta thử nhật một địa điểm mới, ví dụ như "Keangnam Hanoi Landmark Tower", mà không có latitude
và longitude
, Geocoder sẽ lấy những dữ liệu đó từ API bên ngoài và thêm nó vào địa điểm này.
API bên ngoài sẽ được gọi mỗi khi chúng ta cập nhật địa điểm nhưng nó chỉ nên xảy ra mỗi khi trường address
bị thay đổi. Vì vậy, chúng ta nên có một thay đổi đơn giản cho after_validation
callback như sau:
#/app/models/location.rb
class Location < ActiveRecord::Base
geocoded_by :address
after_validation :geocode, if: :address_changed?
end
Nó sẽ chỉ tìm tọa độ mỗi khi address
có sự thay đổi so với lần lưu cuối cùng.
Chúng ta cũng có thể sử dụng phương thức reverse_geocoded_by
để chuyển đổi một latitude
và longitude
thành một address
. Nó cũng làm việc tương tự như phương thức geocoded_by
.
Tìm kiếm những địa điểm gần
Sẽ rất hữu ích khi chúng ta xem một địa điểm lại có thể nhìn thấy danh sách những địa điểm gần nó. Tôi có một số địa điểm trong database, bây giờ, chúng ta sẽ thêm tính năng này cho trang hiển thị một địa điểm.
Tôi muốn liệt kê mỗi vị trí với một khoảng cách nhất định và Geocoder
tạo cho việc lấy các địa điểm lân cận một cách dễ dàng với phương thức nearbys
của nó. Theo mặc định, nó sẽ trả về những địa điểm với bán kính là 20 dặm, nhưng ở đây tôi sẽ giới hạn nó đến 10 dặm thôi.
# /app/views/locations/show.html.erb
<p id="notice"><%= notice %></p>
<h1>Location</h1>
<p>
<strong>Address:</strong>
<%= @location.address %>
</p>
<p>
<strong>Latitude:</strong>
<%= @location.latitude %>
</p>
<p>
<strong>Longitude:</strong>
<%= @location.longitude %>
</p>
<h3>Nearby Locations</h3>
<ul>
<% @location.nearbys(10).each do |location| %>
<li><%= link_to location.address, location %> (<%= location.distance.round(2) %> miles)</li>
<% end %>
</ul>
<p>
<%= link_to "Edit", edit_location_path(@location) %> |
<%= link_to "Destroy", @location, confirm: 'Are you sure?', method: :delete %> |
<%= link_to "View All", locations_path %>
</p>
Mỗi khi chúng ta view một địa điểm, chúng ta sẽ thấy những địa điểm lân cận với nó trong khoảng cách 10 dặm, như sau:
Tiếp theo, chúng ta sẽ thêm một search box trên trang locations index để có thể tìm kiếm những địa điểm lân cận với địa điểm đó.
#/app/views/locations/index.html.erb
<%= form_tag locations_path, :method => :get do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search Near", name: nil %>
<% end %>
<!-- phần còn lại của trang -->
#/app/controllers/locations_controller.rb
def index
if params[:search].present?
@locations = Location.near(params[:search], 10, units: :km)
else
@locations = Location.all
end
end
Hãy thử tìm kiếm với từ khóa "Tổng cục Hải Quan", và xem kết quả hiện thị như sau:
Thêm bản đồ
Khi làm việc với các vị trí địa lý, sẽ rất hữu ích khi ta sử dụng một bản đồ cho mỗi địa điểm. Google Maps API cung cấp nhiều cách để thêm bản đồ tới một trang web, nhưng vì đơn giản nên ở đây tôi sẽ sử dụng một Maps API tĩnh. Bản đồ được thêm vào như một thẻ image_tag
mà URL có các tham số xác định các thông số của bản đồ, bao gồm kinh độ, vĩ độ, kích thước, zoom, vv...
#/app/views/locations/show.html.erb
<%= image_tag "http://maps.google.com/maps/api/staticmap?size=450x300&sensor=false&zoom=16&markers=#{@location.latitude}%2C#{@location.longitude}" %>
Khi đó, trang hiển thị địa điểm sẽ như sau
Nếu bạn muốn sử dụng bản đồ động, hãy thử tham khảo Google Maps For Rails gem.
Trên đây, tôi đã trình bày một số tính năng của gem Geocoder
thông qua một ví dụ nho nhỏ, hi vọng nó sẽ giúp ích được cho bạn đọc
Tài liệu tham khảo
All Rights Reserved