WebOS Goodies

WebOS の未来を模索する、ゲームプログラマあがりの Web 開発者のブログ。

WebOS Goodies へようこそ! WebOS はインターネットの未来形。あらゆる Web サイトが繋がり、共有し、協力して創り上げる、ひとつの巨大な情報システムです。そこでは、あらゆる情報がネットワーク上に蓄積され、我々はいつでも、どこからでも、多彩なデバイスを使ってそれらにアクセスできます。 WebOS Goodies は、さまざまな情報提供やツール開発を通して、そんな世界の実現に少しでも貢献するべく活動していきます。
Subscribe       

Ruby on Rails で郵便番号検索

よく住所を入力するフォームで、郵便番号から住所を自動入力する機能がありますよね。そんなのが必要になったのですが、ググって見つけたサンプルにしっくりくるものがなかったので、自分でちまちま作ってみました。コントローラやビューの部分は公開できる状態ではないのですが、モデルやインポート用の Rake タスクは汎用的に作れたので、本日はそれをご紹介します。

主な特徴は以下のとおりです。

  • 複数回出現する郵便番号は最初のものだけをインポート。
  • 「以下に掲載がない場合」とか「(1丁目〜3丁目)」などという 邪魔なテキストは削除してインポート。
  • "1460082", "146-0082" などの表記の揺れを吸収するファインダ。
  • インポート時には ActiveRecord を使わずに直接SQLを発行しているので、比較的高速・省メモリ。
  • 郵便番号を数値で保存するので、きっと検索が速いと信じたい(^^;

けっこうよく使う処理だと思うので、よろしければご活用ください!

ソースコードとインストール方法

早速ですが、以下が rake タスクのソースコードです。いつもどおりcodeなにがし投稿してあります。

インストール方法というほどのこともありませんが、 "RAILS_ROOT/lib/task" の中に "zip.rake" などのファイル名で保存すれば OK です。

データのインポート方法

それでは郵便番号データをインポートしてみましょう。なお、 Rails アプリケーションはすでに作成されていて、データベースなどが使える状態になっていることを前提にします。

テーブルとモデルを作成する

まずはデータを格納するテーブルがないとどうにもならないので、 migration を使って作成します。ついでにモデルも追加してしまいましょう。 RAILS_ROOT で以下のコマンドを実行してください。

./script/generate model Zip

これで "RAILS_ROOT/lib/???_create_zips.rb" に migration スクリプトが生成されます(??? はバージョン番号)。そのファイルをテキストエディタで開き、以下のように書き換えてください。

class CreateZips < ActiveRecord::Migration
  def self.up
    create_table :zips, :primary_key => 'zip' do |t|
      t.integer :prefecture
      t.string  :city
      t.string  :street
    end
  end
 
  def self.down
    drop_table :zips
  end
end

あとは、 RAILS_ROOT で以下のコマンドを実行すれば、テーブルが作成されます。

rake db:migrate

スキーマは以下のようになっています。

カラム名 データ型 内容
zip integer 郵便番号
prefecture integer JIS X 0401 の県コード
city string 漢字の市区町村名
street string 漢字の町域名

自分が使うデータしか入れてません。すいません。

郵便番号データをダウンロード

元となる郵便番号データは、日本郵政の以下のページからダウンロードできます。

http://www.post.japanpost.jp/zipcode/dl/kogaki.html

県別のデータではなく全国一括のデータをダウンロードしてください。そして、なんとこの時代に LHA 圧縮なので(たしかに LHA は偉大ですけどね!)、なんとかして展開してください。 Windows なら Lhaplus とかでいけるはずです。そういえば、Microsoft 純正のやつもありましたね(笑)。

まあ、とにかく展開すると "KEN_ALL.CSV" という名前のファイルができるはずなので、それを "RAILS_ROOT/db/KEN_ALL.CSV" としてコピーしてください。これで準備完了です。

インポートを実行

あとは Rake タスクを実行するだけです。 RAILS_ROOT で以下のコマンドを実行してください。

rake zip

ちょっと時間がかかるので、気長に待ってください。エラーが出ずに実行が終了すれば、データがインポートされています。 migration の作成時にモデルも追加済みなので、 Rails の console で以下のように検索することができます。

$ ./script/console 
Loading development environment (Rails 2.0.2)
>> Zip.find('1460082')
=> #<Zip zip: 1460082, prefecture: 13, city: "大田区", street: "池上">

あとは、皆さんのアプリケーションでご自由にご利用くださいませ。

表記の揺れに対応する

このままでも使えますが、郵便番号はハイフンなどを削除して完全に数字だけにしないとヒットしません。これではちょっと使いづらいので、この処理を自動で行うモデルを作ってみました。 Zip.find と Zip.find_by_zip をオーバーライドして、数字以外の文字を削除してから検索するようにしています。

class Zip < ActiveRecord::Base
  set_primary_key :zip
 
  instance_eval do
 
    alias :super_method_missing :method_missing
    alias :super_find           :find
 
    def find(id, *args)
      unless Symbol === id && (id == :all || id == :first || id == :last)
        id = id.to_s.gsub(/[^0-9]/u, '')
      end
      super_find(id, *args)
    end
 
    def method_missing(name, *args)
      if name.to_s == 'find_by_zip'
        args[0] = args[0].to_s.gsub(/[^0-9]/u, '')
        result  = super_method_missing(name, *args)
        instance_eval do
          alias :super_find_by_zip :find_by_zip
          def find_by_zip(id) super_find_by_zip(id.to_s.gsub(/[^0-9]/u, '')) end
        end
        result
      else
        super_method_missing(name, *args)
      end
    end
 
  end
 
end

ファインダのオーバーライドがけっこう面倒で、かなり泥臭いことになっています。もうちょっと簡単な方法とかってないんですかね?

まあ、それはいいとして、このモデルを使えば以下のように表記の揺れに対応できます。

$ ./script/console 
Loading development environment (Rails 2.0.2)
>> Zip.find('146-0082')
=> #<Zip zip: 1460082, prefecture: 13, city: "大田区", street: "池上">
>> Zip.find('146 0082')
=> #<Zip zip: 1460082, prefecture: 13, city: "大田区", street: "池上">

注意点

もともと自分で使うためだけに作ったものなので、かなり自分本位な仕様になっています。とくに以下の点にはご注意ください。

  • インポートしているのは郵便番号、県コード、市町村名、町域名のみで、その他のデータは無視しています。
  • 稀にひとつの郵便番号が複数の地域に割り振られているものがあります。このような場合、最初に出てきた地域のみをインポートして、後続のものは無視しています。
  • 郵便番号データのテーブルのプライマリキーは "zip" という名前になっています。モデルを自作する際は注意してください。
  • 県データ(prefecture カラム)は JIS X 0401 の県コードで保存されています。 JIS X 0401 については、 Wikipediaなどを参照してください。
  • すべてのデータをチェックしたわけではないので、もしデータが崩れているものがありましたら、ぜひ教えてください(^^;

以上、本日は Rails に郵便番号検索のデータをインポートする Rake タスクと、それを扱うモデルをご紹介しました。最初は単に CSV をインポートすればいいと思っていたのですが、元データがかなりいけてなくて、なかなか大変でした。これって日本全国でけっこうな労力の浪費が起きてるんじゃないですかね。ゴミデータを含まない XML 形式の郵便番号データを切に望みます>日本郵政さん

関連記事

この記事にコメントする

Recommendations
Books
「Closure Library」の入門書です。
詳しくはこちらの記事をどうぞ!
Categories
Recent Articles