##はじめに
作成しているwebサービスで駅のデータが必要だったので色々調べたところ、データベースに保存できました。せっかくなので記事に残しておきます。
※筆者は初学者です。文章に誤りがあったらコメント等で教えてください。
4/18加筆 lonとlatの型を間違っていたため:integer
を:decimal
に変更しました。
##筆者の環境
Rails 5.1.7
ruby 2.5.7
※他に必要な情報ありましたら教えて下さい。
##csvファイルをダウンロードしたサイト
無料のものだったり有料のものだったりありますが、
私はこのページでダウンロードしました(この記事と同じようにしたい方は駅データの2020-03-16
をダウンロードしてください)。
一部の情報は有料ですが、その情報も4,400円ってすごいですね。駅データの仕様書とかも同じサイトにあるので詳しくはそこで見てね。
他のデータ配布サイトも知りたいって方はこの記事にまとめられてます。
######ここでダウンロードしたファイルはdb配下にcsvディレクトリを作成後、ファイル名をstation_data.csvに変えて、アプリケーションからの相対パスがdb/csv/station_data.csv
となるように保存してください。
##Railsでcsvファイルをインポート
###データを入れるデータベースを準備する
まずモデルを作成します。
$ rails g model station_data #dataはdatumの複数形なので名前のつけ方が悪いかも...
次にこの時に作成されたマイグレーションファイルを駅データの型に合わせて次のように編集します。いらないと思った情報は含めないようにしているので、必要な方はそれらも追加してください。(例: 駅がある場所の郵便番号が欲しいならt.string :post
を追加するなど)
class CreateStationData < ActiveRecord::Migration[5.1]
def change
create_table :station_data do |t|
t.integer :station_g_cd
t.string :station_name
t.integer :line_cd
t.integer :pref_cd
t.string :address
t.decimal :lon
t.decimal :lat
t.timestamps
end
end
end
変更をデータベースに反映させます。
$ rails db:migrate
###csvファイルをインポートするためのコードを書く
lib/tasks/import.rake
(新しく作成)に次のコードを記入します。
require 'csv'
# rake import:station_data
namespace :import do
#このdescはdescribeのdesc
desc "Import station_data from csv"
task station_data: :environment do
path = File.join Rails.root, "db/csv/station_data.csv"
puts "path: #{path}"
list = []
CSV.foreach(path, headers: true) do |row|
list << {
station_g_cd: row["station_g_cd"],
station_name: row["station_name"],
line_cd: row["line_cd"],
pref_cd: row["pref_cd"],
address: row["address"],
lon: row["lon"],
lat: row["lat"]
}
end
puts "start to create station data"
begin
StationDatum.create!(list) #クラス名注意
puts "completed!!"
rescue ActiveModel::UnknownAttributeError => invalid
puts "raised error : unKnown attribute "
end
end
end
軽くコードの解説をしますとCSV.foreach
でpath
にあるcsvファイルから1行ずつ読み込んでいます。読み込まれた行はlist
という空の配列に{station_g_cd: 1110110, station_name: 函館,....}
のような形のハッシュを追加していっています。
補足: headers: true
には1行目をヘッダ行として無視する役割があるそうです。
コードを書けたらターミナルで次の一文を出力して終わりです!
$ rake import:station_data
これでdb/development.sqlite3
を特定のツールで確認してみると駅のデータが反映されていると思います。お疲れ様でした。
##おまけ(重複したデータの削除)
今回使用した駅データは、同じ場所の駅でも路線が違ったりすると別のレコードで記録されています(どの駅データでもそうなっていると思いますが)。私はユーザーと最寄り駅を紐付けたかったのですが、一人のユーザーが複数の駅データと紐ずくとまずいと思ったので、重複したデータを1つだけ残して他は削除しました。
コードの説明などは参考にしたサイトからお願いします。次の2つのコードできれいに削除できます。
$rails c
irb(main):001:0> hash = StationDatum.group(:station_g_cd).having('count(*) >= 2').minimum(:id)
irb(main):001:0> StationDatum.where(station_g_cd: hash.keys).where.not(id: hash.values).destroy_all
※ :station_g_cd
は一つの駅ごとに一つだけ与えられているコードであることを利用しています。
##終わりに
ここまで読んでくださってありがとうございました。
https://qiita.com/kou/items/e0d3fab106e4c52a7f26
このサイトでも紹介されてる「駅すぱあとAPI」とかを理解が進むと使ってみたいです。使って理解できたらまたまとめると思います。
##参考にしたサイト
インポートのために書いたコードの意味の理解で用いました。
http://www.code-magagine.com/?p=8004
全てはこの記事と言っても過言ではない。本当に感謝。
https://qiita.com/yoshito410kam/items/40b675760bd8a1f8e728
重複したデータの削除についてはここ。
https://qiita.com/wakasa51/items/efe2b4b3554a50d18c32