12/08/2018, 13:16

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.

0