Ruby

【Rails】seedコマンドでcsvからデータを投入する方法

Railsでは、seedコマンドでDBにデータを投入することができます。

通常はdb/seeds.rbに投入したいデータを記述しますが、可読性が低くなってしまいます。

そこで投入するデータをCSVファイルに記述することで、データの中身も確認しやすく便利になりますので紹介します。

ディレクトリー構成

今回ディレクトリー構成は、以下のような構成とします。

dbディレクトリー構成配下にseeds.rbを作成して、テーブル名.csvのファイルを作成します。

例えばPrefectureモデルのデータを投入したい場合、prefectures.csvファイルを作成します。

app
  ├ models
    ├ <モデル>
db
  ├ seeds.eb
  ├ seeds
     ├ <CSVファイル>

CSVファイル

CSVファイルにはヘッダーを記述して、モデルの属性とマッピングさせます。

id,code,name,name_kana
1,01,北海道,ホッカイドウ
2,02,青森県,アオモリケン
3,03,岩手県,イワテケン

CSVを読み込んでDBに投入する処理を記述

db/seeds.rbにCSVを読み込んで、DBに投入する処理を記述します。

model_namesの変数に、seed対象のモデルを記述します。

モデル名をテーブル名に変換して、CSVファイルのデータを1件ずつ検索を行います。

そしてデータがあれば更新、データがない場合は新規で保存します。

require 'csv'

model_names = %w(Prefecutre)

model_names.each do |model_name|
  model = model_name.constantize
  table_name = model.table_name
  CSV.read("#{Rails.root}/db/seeds/#{table_name}.csv", headers: true).map(&:to_h).each do |model_params|
    if model.exists?(id: model_params["id"])
      record = model.find(model_params["id"])
      record.update(model_params.dup.delete_if {|_,v| v.blank?})
    else
      record = model.new(model_params.dup.delete_if {|_,v| v.blank?})
      record.save
      if Rails.configuration.database_configuration[Rails.env]["adapter"] != "sqlite3"
        ActiveRecord::Base.connection.execute("select setval('#{table_name}_id_seq',(select max(id) from #{table_name}))")
      end
    end
  end
end

まとめ

初期データをseedファイルに記述すると、データの可読性が下がり辛くなることがよくあります。

CSVファイルにデータの中身を記述することで、データを追加するのも簡単にできますので参考にしてみてください。

-Ruby

Copyright© てくてくライフ , 2020 All Rights Reserved.