+8

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/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ó classcompany_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ề OKtypepostal_code.

company_address.val(address); để đẩy address nhận được vào box input có idcompany_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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí