Chuyển đổi từ postal_code thành address
Bài đăng này đã không được cập nhật trong 8 năm
Trong công việc của bạn, đôi khỉ phải chuyển đổi từ postal_code
thành address
, dự án mình có động đến phần này nên muốn chia sẻ 1 ít kinh nghiệm, khách hàng là người Nhật nên mình chia làm 2 phần, đối với postal_code
của Nhật và phần còn lại.
Phần postal_code
của Nhật (http://qiita.com/inodev/items/8a9230a3f245967f6e22) thực chất là down về 1 file CSV chứa các postal_code
và địa chỉ đầy đủ của Nhật, phần còn lại dùng Google Maps Geocoding API (https://developers.google.com/maps/documentation/geocoding/intro)
I. Tạo dữ liệu postal_code của Nhật:
Làm theo như hướng dẫn tại link (http://qiita.com/inodev/items/8a9230a3f245967f6e22) ta tạo model lưu giữ postal_code và địa chỉ tương ứng:
class CreateMPostalCodeAreas < ActiveRecord::Migration
def change
create_table :m_postal_code_areas, options: "ROW_FORMAT=COMPRESSED" do |t|
t.string :postal_code, null: false
t.string :prefectural, default: ""
t.string :city, default: ""
t.string :street, default: ""
t.timestamps null: false
end
end
end
File CSV down về theo như link hướng dẫn (sau khi qua các bước ta được convert) gồm các cột postal_code, prefectural, city, street
, chú ý là postal_code trong file thiếu số 0 ở đầu cho đủ 7 kí tự, do vậy trong model ta thêm def convert_postal_code
để tạo đủ số ký tự cho postal_code.
class M::PostalCodeArea < ActiveRecord::Base
POSTAL_CODE_LENGTH = 7
PREFIX_POSTAL_CODE_NUMBER = 0
scope :by_postal_code, ->postal_code{where postal_code: postal_code}
before_save :convert_postal_code
def address
[prefectural, city, street].compact.join
end
private
def convert_postal_code
return true if postal_code.length >= POSTAL_CODE_LENGTH
self.postal_code = prefix_postal_code << postal_code
end
def prefix_postal_code
PREFIX_POSTAL_CODE_NUMBER.to_s * (POSTAL_CODE_LENGTH - postal_code.length)
end
end
Như vậy ta đã tạo được dữ liệu cho phần postal_code của Nhật.iệu
II. Lấy dữ liệu từ Google Maps Geocoding API
Link tham khảo (https://developers.google.com/maps/documentation/geocoding/intro#geocoding)
Thử lấy dữ liệu bằng link https://maps.googleapis.com/maps/api/geocode/json?address=10007 ta được:
{
"results" : [
{
"address_components" : [
{
"long_name" : "10007",
"short_name" : "10007",
"types" : [ "postal_code" ]
},
{
"long_name" : "Lower Manhattan",
"short_name" : "Lower Manhattan",
"types" : [ "neighborhood", "political" ]
},
{
"long_name" : "Manhattan",
"short_name" : "Manhattan",
"types" : [ "sublocality_level_1", "sublocality", "political" ]
},
{
"long_name" : "New York",
"short_name" : "New York",
"types" : [ "locality", "political" ]
},
{
"long_name" : "New York County",
"short_name" : "New York County",
"types" : [ "administrative_area_level_2", "political" ]
},
{
"long_name" : "New York",
"short_name" : "NY",
"types" : [ "administrative_area_level_1", "political" ]
},
{
"long_name" : "United States",
"short_name" : "US",
"types" : [ "country", "political" ]
}
],
"formatted_address" : "New York, NY 10007, USA",
"geometry" : {
"bounds" : {
"northeast" : {
"lat" : 40.717076,
"lng" : -74.0001781
},
"southwest" : {
"lat" : 40.709806,
"lng" : -74.01375399999999
}
},
"location" : {
"lat" : 40.7136487,
"lng" : -74.0087126
},
"location_type" : "APPROXIMATE",
"viewport" : {
"northeast" : {
"lat" : 40.717076,
"lng" : -74.0001781
},
"southwest" : {
"lat" : 40.709806,
"lng" : -74.01375399999999
}
}
},
"place_id" : "ChIJwbJsUhhawokRuCRdc8piF8c",
"types" : [ "postal_code" ]
}
],
"status" : "OK"
}
Chú ý dòng "types" : [ "postal_code" ]
đây là option dạng dữ liệu đưa về.
Ta cũng có thể vào 1 đường link https://maps.googleapis.com/maps/api/geocode/json?address=ha noi, kết qủa trả về sẽ có "types" : [ "country", "political" ]
III.Gép 2 cách lấy address
Dùng js để lấy dữ liệu như sau, tại form input zipcode, ta gán id cho nó, ví dụ là id có name là company_zipcode
nằm trong div có class
là company_entry
$(".company_entry").on("change", "#company_zipcode", function(){
var zipcode = $("#company_zipcode").val();
$.get("/ajax/m/postal_code_areas/", {postal_code: zipcode});
});
Đoạn code này để bắt sự kiện thay đổi trong phần input company_zipcode
, sau đó gọi đến controller postal_code_areas
để xử lý, params được đưa vào là gía trị của box có id
company_zipcode
.
Controller của PostalCodeAreasController
như sau:
class Ajax::M::PostalCodeAreasController < ApplicationController
def index
@postal_code_areas = M::PostalCodeArea.by_postal_code params[:postal_code]
end
end
Tại form input ta thêm:
<% content_for :assets do %>
<%= javascript_include_tag "https://maps.googleapis.com/maps/api/js?v=3" %>
<% end %>
Tại file index.js.erb
của phần view postal_code_area
var company_address = $(".company_entry #company_address");
<% if @postal_code_areas.any? %>
company_address.val("<%= @postal_code_areas
.map(&:address).join I18n.t('.postal_code_address_seperator') %>");
relate_validate(company_address);
<% else %>
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ "address": "<%= params[:postal_code] %>"}, function(results, status){
if ((status == google.maps.GeocoderStatus.OK) && check_results(results)){
var address = results[0].formatted_address;
company_address.val(address);
}
});
<% end %>
function check_results(results) {
return (results[0].address_components[0].types[0] == "postal_code");
}
<% if @postal_code_areas.any? %>
để check xem postal_code
được đưa vào có tìm thấy trong bảng PostalCodeArea
hay không.
Chú ý hàm check if ((status == google.maps.GeocoderStatus.OK) && check_results(results))
để check điều kiện dữ liệu trả về OK
và type
là postal_code
.
company_address.val(address);
để đẩy address
nhận được vào box input có id
là company_address
.
Như vậy ta đã có thể vừa lấy address
từ postal_code
theo file CSV hoặc dùng Google Maps Geocoding API.
Cảm ơn và hi vọng bài viết gíup ích trong công việc của ban.
All rights reserved