【Ruby on Rails】seedとseed_fuの違い・CSVファイルで読み込ませる方法

# 概要
Ruby on Railsにて、itemの初期データを大量に一括登録した。
* `seed`と`seed-fu`を使ってデータ登録を行う場合の違い
* CSVファイルで初期ファイルを作って読み込ませる方法
* CSVファイルの日本語が文字化けした場合の対処法
* herokuでのデプロイ方法

も、まとめてメモしておく。

結論、seed-fuを使った方がおすすめ。

# 前提
* ADMINによる管理者ユーザー追加も可能であるが、今回は随時データ増えるものではない前提とする。
    * 映画口コミサイト・レストラン口コミサイトなどは数が可変的なのでADMINが必要と思われる
* 初期データはソースコードにベタ打ちすることも可能だが、今回はCSVファイルで一括記載したものを読み込む手段を使う。その方が中身を変えることがあるときに簡単なため。

# seed.rbを使う場合の手順
* itemの初期データを記載したCSVファイルを、`db/items.csv`に配置(命名)する。　
* rowとレコードの関連付けはそれぞれ設定してください。
```db/seeds.rb
require "csv"

CSV.foreach('db/items.csv') do |row|
Item.create(:item_name => row[0], :description => row[1], :image_url => row[2], :star => row[3])
end

```
* これで、以下コマンドを実行すれば登録される。
    * `rails db:migrate`
    * `rails db:seed`

* なお、herokuデプロイ時は　以下コマンドを実行する。
    * `heroku run rails db:migrate`
    * `heroku run rails db:seed　`


# seed-fuを使う場合の手順（おすすめ）
* seed.rbでも登録は可能。ただし、初期データを登録してもリリースまでに何度も中身を更新する可能性がある。その際に、一回一回`db reset`しなくてはならないと作業が大変である。そこで、`seed-fu`というgemを利用する。
* gemfileに `gem 'seed-fu'`　と記載して`bundle install`を実行する。
* `db/fixtures/development`に`01_item.rb`を作成し、コードを記載する。CSVファイルはdb/fixtures以下に保存。

```db/fixtures/development/01_item.rb 
require 'csv'

csv = CSV.read('db/fixtures/items.csv', encoding: 'UTF-16')
csv.each do |row|
  item_id = row[0]
  item_name = row[1]
  description = row[2]
  image_url = row[3]
  star = row[4]

  Item.seed(:item_id) do |s|
    s.item_id = item_id
    s.item_name = item_name
    s.description = description
    s.image_url = image_url
    s.star = star
  end
end
```

* `rails db:seed_fu`を実行すれば反映される

* なお、herokuデプロイ時は`heroku run rails db:seed_fu`で実行する
* ただし、2回目以降は、`heroku run rails db:seed_fu`を実行すると、`Running rails db:seed_fu on...xxx up, run.7916 (Free)　`で終わってしまう。このエラーを解決できなかった（誰か知っていたら教えてください...後述）ため、上記コードをもともと使っていた`db/seeds.rb`に貼り付けた。これであれば更新時も、重複分が重複登録されず、綺麗に更新できる。

```db/seeds.rb 
require 'csv'

csv = CSV.read('db/fixtures/items.csv', encoding: 'UTF-16')
csv.each do |row|
  item_id = row[0]
  item_name = row[1]
  description = row[2]
  image_url = row[3]
  star = row[4]

  Item.seed(:item_id) do |s|
    s.item_id = item_id
    s.item_name = item_name
    s.description = description
    s.image_url = image_url
    s.star = star
  end
end

```

* なお、`seed.rb`にて一意性制約を設けた方が良い。seed メソッドに引数`:item_id`を付ければOK。
    * これによって、`seed-fu`は「どの seed が変更されたか」を判断することができるようになる。

# CSVファイルの日本語が文字化けする場合（"\xFF" on Shift_JISエラー）
* CSVファイルをVScode上で編集すると文字化けすることがある。
    * 文字コードを「Shift_JIS」もしくは「Unicode（UTF-16）」に変更して保存。
* `rails db:seed_fu`で"\xFF" on Shift_JISエラーが出たので、`encoding: 'UTF-16'`としたら解決した。

# herokuデプロイ時のエラー(?)について
* `git push heroku main` でデプロイはできていること確認済。
* `heroku run rails db:migrate` で　 `Running rails db:migrate on...`と表示され、以下のように表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/2d58620f-509f-e2ba-182b-aa88c102b3eb.png)

* `heroku run rails db:seed_fu`を実施すると、`Running rails db:seed_fu on...xxx up, run.7916 (Free)` で終わってしまう、というのが困っていること。（数字はいつも違いますが何度やっても途中で終わってしまっているみたい）


* やってみたこと
    * `heroku run rails db:seed` →seed.rbの方は何も記載していないのでもちろん反応せず
    * `heroku run bundle exec rails db:seed_fu RAILS_ENV=production　`　→変わらず
    * `heroku run rails db:migrate:reset`→DISABLE~以降をつけてなさいとエラー（以下）が出たので`heroku run rails db:migrate:reset DISABLE_DATABASE_ENVIRONMENT_CHECK=1`でリセット。`heroku run rails db:check_protected_environments`の実行後、`heroku run rails db:create`、`heroku run rails db:migrate`、`heroku run rails db:seed_fu`を再度実施し直してみたが、反映されず。
    * herokuはid連番の必要がある？という記事も見つけたので、item_idカラムを作成、番号を振ってみたが、何も変わらず。
        * [Herokuの本番環境でseeds.rbの内容が反映されなった件](https://qiita.com/yunyun_engineer/items/f719c9f7e885d4cab1e1)

* 上記、2022.6.19にteratailで質問しましたが、回答なく撃墜。上記記載の一意性制約で対応としました。
    * [heroku run rails db:seed_fu が反映されません](https://teratail.com/questions/dk95ovz03sokxc)