【Rails】郵便番号から住所を自動入力する機能の作り方

Ruby on Rails6 で郵便番号から住所を自動入力する機能を導入したのですが,忘れないうちに手順を備忘録として残しておきます。ここでは,外部のAPIを使わずにサイト内にデータベースを入れて検索します。手順をちゃんと踏めば,作業はそれほど難しくはないです。なお,ここではセキュリティ関係を考慮していません。

データの入手と加工

郵便番号データのダウンロードから「全国一括データ」をクリックしてダウンロード。

ファイルを解凍して,KEN_ALL.csv を Excel などで開く。

左から3列目の7桁の数字(郵便番号)と,7~9列目(都道府県,市区町村,町名)の4つの列だけ必要なので,その他の列は削除する。

文字コードを Unicode(UTF-8)で指定して保存する。

テーブルの作成

Rails のターミナルに以下を入力して,テーブル Postal を作成。

rails g model Postal postal_code:integer prefecture:string city:string town:string

テーブル Postal は4つのカラム,potal_code(郵便番号),prefecture(都道府県),city(市区町村),town(町名)を持つ。ここにデータを流し込む。テーブル作ったら rails db:migrate を忘れずに。

db フォルダに KEN_ALL.csv を移動させる。同じ db フォルダ内にある seed.rb を開いて以下を入力。

CSV.foreach("db/KEN_ALL.csv", encoding: 'UTF-8') do |info|
  Postal.create(
    postal_code: info[0],
    prefecture: info[1],
    city: info[2],
    town: info[3],
    )
end

ターミナルから以下を入力して,seedファイルから初期データを生成する。レコード数が12万件ほどあるので作成には時間がかかる。

rails db:seed

rails c でコンソールを立ち上げ,ためしに Postal.find(10) などを入力して,以下のような出力が返ってくればデータの作成が成功している。

created_at: Fri, 25 Feb 2022 12:05:55.154134000 JST +09:00,
updated_at: Fri, 25 Feb 2022 12:05:55.154134000 JST +09:00,
postal_code: 600002,
prefecture: "北海道",
city: "札幌市中央区",
town: "北二条西">

API の設置

仕組みとしては API を設置して,郵便番号を送ると住所が JSON 形式で返ってくるようにする。これを Javascript でフィールドに格納する。

まずは,config/routes.rb に以下を追加。

  get "search/:postal_code" => "search#postal_code"

アドレスバーに localhost:3000/search/4620003 などと入力すれば,郵便番号 4620003 に対応する住所が格納された JSON 文字列が出力されることになる。

次に,コントローラ search を作成。

rails g controller search

コントローラー app/controllers/search_controller.rb の中身は以下のようにする。

class SearchController < ApplicationController

  def postal_code
    @postal_code = Postal.find_by(postal_code:params[:postal_code])
    render json: @postal_code
  end

end

上の例で言えば,params[:postal_code] = 4620003 となっている。find_by でテーブル Postal のカラム postal_code から一致するレコードを抽出する。あとは,render json: でレコードを JSON 形式で出力することができる。

ためしに,localhost:3000/search/4620003 を入力してみて,画面に以下の文字列が表示されれば,API が機能していることになる。

{"id":66886,"created_at":"2022-02-25T12:10:02.294+09:00","updated_at":"2022-02-25T12:10:02.294+09:00","postal_code":4620003,"prefecture":"愛知県","city":"名古屋市北区","town":"桐畑町"}

フォームの作成

app/views/user/new.html.erb などのファイルにフォームを設置する。フォームの中に検索ボタンを設置していく。

最後の <%= javascript_pack_tag 'search' %> は Javascript のファイル,app/javascript/search.js を参照する。このファイルはあとで作成する。

また,このタグは最後に書くようにする。HTMLファイルでも<script>のタグは最後に書くのと同じ理由。最初に書くと動かなくなるので注意。

<%= form_with( ・・・・・・ ) do |f| %>
  <%= f.text_field :postal_code, size:7 %>
  <p>例:4620003(半角数字)</p>
  <p class="search-postal-code">郵便番号から自動入力</p> #文字をクリックしたら住所を自動入力
  <p class="search-postal-code-error"></p>

  <%= f.text_field :address, size:60 %>
  ・・・・・・

  <%= f.submit ・・・・・・ %>
<% end %>

<%= javascript_pack_tag 'search' %>

ブラウザからページを表示して,テキストボックスの部分を右クリック→「検証」をクリックすると画面右側で

<input size="7" type="text" value="4620003" name="user[postal_code]" id="user_postal_code">

のように,実際に表示される HTML コードが確認できる。ここで,id を確認しておく。同様に,住所を反映させるテキストボックスの id も確認しておく。

Javascript

app/javascript/packssearch.js を新規作成する。中身は以下。

document.querySelector('.search-postal-code').addEventListener('click', () => {
  const postalCode = document.querySelector("#user_postal_code");
  fetch("/search/"+postalCode.value)
    .then((data) => data.json())
    .then((obj) => {
      if(obj === null) {
        const elem = document.querySelector(".search-postal-code-error");
        elem.innerHTML = "該当する住所が見つかりません。";
      } else {
        const address = document.querySelector("#user_address");
        address.value = obj.prefecture + obj.city + obj.town;
        const error = document.querySelector(".search-postal-code-error");
        error.innerHTML = "";
      }
    });
});


「郵便番号から自動入力」のところにイベントリスナーを設置。

クリックされたら,今度は郵便番号が入力されているテキストボックスから入力された値を取り出し,fetch で API を叩く。

あとは,住所を入力するテキストボックスに都道府県+市区町村+町名を連結した文字列を格納する。

入力した値に該当する住所が存在しない場合,null を返すので,エラーメッセージを表示する。