Chuyển đổi từ postal_code thành address
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/ite ...
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.