【Rails】seeds.rbの書き方・ローカルや本番環境用コマンド

こんばんは！
ポートフォリオもいよいよ終盤でテストデータを増やしてアプリケーションの見栄えを良くしたいなと思い、seeds.rbへコードを書いてみたもののなかなかうまく動かなかったり、自分が得たいデータの出し方が分からなかったりと苦戦してなんとかできたので、私と同じ初心者の方の参考になるといいなと思い投稿してみました。

コマンド早見は右側の目次から選ぶとスムーズに見れます。

## seeds.rbとは
　seeds.rbとはdbフォルダの中に入っており、テスト段階などで初期データ数を増やしたいときに手動で登録の作業をするのは大変なので、予め記述しておくと簡単にデータを反映させることができる優秀なファイルです！作るのは大変ですが、一度作ると後からとても楽です。
 テストをするうえではサンプルデータ数の多い方がよりバグに気付きやすいので、そういった点でも入れるべきだと思います。

 ## 書き方と説明

 ### deviseを導入しており管理者データを入れる場合
 ```rb:db/seeds.rb
 Admin.find_or_create_by!(email: 'admin@admin') do |admin|
  admin.password = ENV["SECRET_KEY"]
end

 ```
上記は***管理者データ登録***のコードです。
1行目は`.find_or_create_by!`メソッドのあとに続く()の中身を確認し、()の中身と同じデータを探してなければ新規作成するようにしています。このメソッドを使う時は、do |変数|　~ endを必ず使うようにしましょう。その1行下に、()以外の`テーブル名.登録したいカラム名 = 登録するデータ`を中身に入れています。今回は管理者機能が不正利用されないよう.envにパスワードを記述しています。

### ユーザーデータを登録したい場合
 ```rb:db/seeds.rb
10.times do |n|
  User.find_or_create_by!(email: "test#{n + 1}@hoge") do |user|
    user.nickname = "テストユーザー#{n + 1}"
    user.introduction = "テストユーザーです。"
    user.password = "testuser#{n + 1}"
  end
end
 ```
こちらは***ユーザー登録***のコードです。
今回10人分データを作りたいとおもったので、10回同じ処理を繰り返すように`10.times do |n|`で指示しています。数字を変えれば必要な数だけユーザーを登録できます。

(みんな名前がテストユーザーじゃ嫌だ！という方は、この1つ下の投稿内容のデータの入れ方を参考にし、データを作ってみてください。自分でデータ内容を決めてカスタムすることもできます。)

`10.times do |n|`の中にユーザーを登録するメソッドを書いています。管理者側と同様、`.find_or_create_by!`メソッドのあとに続く()の中身を確認し、()の中身と同じデータを探してなければ新規作成するようにしています。

メールアドレスを作る際には"test#{n + 1}@hoge"を10回繰り返すので、test1@hoge, test2@hoge...というようにデータが作られていきます。
その下に、`テーブル名.カラム名　= 登録データの中身`となるようにしています。先ほどのメールアドレス以外の情報を入れていきます。

::: note warn
NOT NULL制約をしているカラム、バリデーションをしているカラムは正しくデータを入れないとエラーが出てしまうため、注意してデータを入れてください！
:::
:::note warn
deviseのパスワードは、マイグレーションファイルにはカラム名がencrypted_passwordとありますが、seeds.rbではpasswordと入れないとデータ登録できません！
:::

### データを好きなようにカスタムして投稿などのデータを登録する
```rb:seeds.rb
goals = [
   {title: "筋トレを毎日する", content: "家で毎日30分筋トレをする", category: 2 , reward: "新しいプロテイン購入"},
   {title: "英検2級を取得する", content: "単語を1日30個ずつ覚える", category: 1, reward: "漫画を買う" },
   {title: "家を綺麗な状態に保つ", content: "毎晩散らかしたものをもとに戻す", category: 3, reward: "自分をほめる" },
   {title: "課長になる", content: "資格取得をする", category: 4, reward: "飲み会に行く"},
   {title: "肌をきれいにする", content: "ニキビ治療、生活習慣の改善をする", category: 5, reward: "いろんなメイクに挑戦する"},
]


goals.each do |goal|
  # 一度目標をタイトルで検索し、見つからなければデータを作成する
  Goal.find_or_create_by(title: goal[:title]) do |g|
    g.content = goal[:content]
    g.user_id = User.all.ids.sample
    g.category_id = goal[:category]
    g.deadline = Random.rand(DateTime.new(2024, 5, 1) ... DateTime.new(2025, 1, 1))
    g.reward = goal[:reward]
  end
end
```
今回は目標の投稿に関するデータを書いたので、データ自体が変なのは気にしないでください:innocent:

まずは作成メソッドを書く前に、予めデータを配列で定義しておきます。一つのデータで`{カラム名: "データ", カラム名: "データ"...}`となるようにし、作りたいデータの数だけ{}で囲みます。

IDなどは""(クォーテーション)で囲まないでOKです！

そのあとの記述は、`定義したデータの変数.each do |変数|`となるようにし、そこにさらにユーザー作成などでも使った`.find_or_create_by!`メソッドを使用し、同じデータがないか検索します。

ここでどのカラムを使って検索するかはお任せしますが、投稿であればタイトルが被らない方がいいと思ったためタイトルが同じものがなければ作成するように書きました。投稿ごとにどこが被ってほしくないかを考えて決めましょう。逆に他と数字や内容が被るデータを検索に使うとせっかく書いたデータを作れないということになってしまうので気を付けましょう。

***少し応用***
今回はネストして入れているデータで、自分で定義していたものと、ランダムで選んでもらえるようなものが混ざっています。もし興味があれば数字や日付をランダムで選んでもらうメソッドの説明を書いたので、以下も参考にしてみてください。

`User.all.ids.sample`というように書いている部分は、すべてのUserテーブルのidの中から、`.sample`メソッドを用いて、ランダムに中身を取り出して使うように指示しています。

`Random.rand(DateTime.new(2024, 5, 1) ... DateTime.new(2025, 1, 1))`では、**datetime**をデータ型に使っている場合、日付をこの日からこの日までの中でランダムで選択するように指定しています。







## seeds.rbに関するコマンド早見(ターミナル)
### ローカル
seeds.rbのデータをローカルのデータベースに登録
```
rails db:seed
```
ローカルのデータベースをリセット+seeds.rbのデータ読み込み
```
rails db:reset
```

### 本番環境
データベースのリセット
```
RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rails db:drop
rails db:create RAILS_ENV=production
rails db:migrate RAILS_ENV=production
```
seeds.rbのデータ反映
```
rails db:seed RAILS_ENV=production
```

## 最後に
もう少しでポートフォリオ制作が終わりスクール卒業目前ですが、楽しくプログラミングをでき、スクール内で友達もでき、そしてメンターさんにもいつも知識をいただき人間としても成長できたような3か月間でした。社会人として無職経験は初めてでしたが、とても良い思い出ができ、人生を変える3か月でもあったなと思います。