柳屋

ソースコードのリファクタからよもやままで

Rails5で都道府県、市区町村のマスターデータをワンライナーで作成

郵便局が提供している郵便番号データから都道府県と市区町村のMySQLのマスタデータをワンライナーで作成します

処理の流れ

  • 郵便番号データを郵便局のサイトからダウンロード
  • ダウンロードしたZIPファイルを解凍し保存
  • 保存したCSVファイルを読み込みMySQLに保存

テーブル作成

最終的に完成するテーブルは以下のようになります 今回は必要最小限の構造となってます。

都道府県テーブル

id name
1 北海道
2 青森県

市区町村テーブル

id pref_id name
1 1 札幌市北区

マイグレーション

都道府県テーブル

class CreatePrefs < ActiveRecord::Migration[5.1]
  def change
    create_table :prefs do |t|
      t.string :name, :limit => 4, :unique => true

      t.timestamps
    end
  end
end

市区町村テーブル

class CreateCities < ActiveRecord::Migration[5.1]
  def change
    create_table :cities do |t|
      t.integer :pref_id
      t.string :name, :limit => 16

      t.timestamps
    end
  end
end

マイグレーション実行

マイグレーションを実行しテーブル作成

rails db:migrate

seedファイル

今回は初期データを追加するので db/seeds.rbに追記していきます

require 'csv'
require 'zip'

DLURL           = "http://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip"
SAVEDIR         = "db/"
CSVROW_PREFNAME = 6
CSVROW_CITYNAME = 7

savePath = ""

# 住所CSVダウンロード、解答し保存
open(URI.escape(DLURL)) do |file|
  ::Zip::File.open_buffer(file.read) do |zf|
    zf.each do |entry|
      savePath = SAVEDIR + entry.name
      zf.extract(entry, savePath) { true }
    end
  end
end

# 住所CSVを読み込みDBに保存
CSV.foreach(savePath, encoding: "Shift_JIS:UTF-8") do |row|
  prefName = row[CSVROW_PREFNAME]
  cityName = row[CSVROW_CITYNAME]
  pref = Pref.find_or_create_by(:name => prefName)
  City.find_or_create_by(:name => cityName, pref_id: pref.id)
end

File.unlink savePath

seed実行

以下コマンドで上記スクリプトを実行するとデータが完成

rails db:seed
;(function(document){ var pres = document.getElementsByTagName("pre") for(var i=pres.length; i--; ){  var el = makeOl(pres[i]) pres[i].appendChild(el) } function makeOl(pre){ if (pre.className.indexOf("gist") !== -1) { return } var ol = document.createElement("ol") , li = document.createElement("li") , df = document.createDocumentFragment() , br = pre.innerHTML.match(/\n/g) || 0 ol.className = "preLine" ol.setAttribute("role", "presentation") // no lang, no line-number if( pre.className && ! /lang-./.test(pre.className) ){ br.length += 1 } for(var i=br.length; i--; ){ var li2 = li.cloneNode(true) df.appendChild(li2) } ol.appendChild(df) return ol } })(document)