見出し画像

【31】【Rails】本番環境ではrails db:reset使えないよ。さあどうする?

この記事を読むとrails db:resetが使えない環境下でデーターベースを変更する手段を学ぶことができます

事前準備

(rails new、モデルの作成などのコマンドは割愛します)
Customerモデルがあり:birthdayカラムがあるとします。

customers,  :birthday, :date
seedファイル
 100.times do
   Customer.create!(
   #現在時刻から60年前に遡り、x秒進む。xは40年の範囲で乱数表示された値
     birthday: 60.years.ago.advance(seconds: rand(40.years)).to_date
     )
     end
入力フォーム
<div>
 <%= f.label :birthday,"生年月日" %>
 <%= f.date_field :birtyday %>
</div>

要件の変更

ここで要件が変わりました。アプリの機能が拡張され、Customerモデルを検索する際、年指定、月指定、日数の指定で検索できるようにします。
そこで、Customerモデルに、
birth_year
birth_month
birth_mday
を追加します。

これでbirth_monthやbirth_mdayを参照することで、要件に合った検索ができるようになります。

しかし、問題があります。
既存のbirthdayカラムをどうすればいいでしょうか?
また、すでにデータベース登録されているCustomerは新しく追加された項目がnullになっています。

既存のbirthdayカラムをどうするか?

既存のbirthdayカラムはそのまま使います。入力フォームも変更しません
では、どのようにして、birth_year、birth_month、birth_mdayに値をいれればよいのでしょうか?

before_saveメソッド使います。
モデルが保存される前に、birthdayを、birthday.year,birthday.month,birthday.mdayと分割し、
それぞれのカラムに入れていけばいいのです。

 before_save do
   if birthday
     self.birth_year = birthday.year
     self.birth_month = birthday.month
     self.birth_mday = birthday.mday
   end
 end

既存のデータベースの変更

次に、nullの件について対応します。
すでにデータベース登録されているCustomerは新しく追加された項目がnullになってますよね。
開発環境では、rails db:resetをすれば、nullがなくなります。
しかし、本番環境ではどうでしょうか?
リセットなんか絶対にできません。

SQL文を使う
この場合はSQL文を用いてデータベースを直接変更します。

rails g migration update_users1
 def up
   execute <<~SQL
     UPDATE users SET birth_year = EXTRACT(YEAR FROM birthday),
       birth_month = EXTRACT(MONTH FROM birthday),
       birth_mday = EXTRACT(DAY FROM birthday)
       WHERE birthday IS NOT NULL;
   SQL
 end
def down
   execute <<~SQL
     UPDATE users SET birth_year = NULL,
     birth_month = NULL,
     birth_mday = NULL
   SQL
 end

downメソッドを必ず明記する

SQL文の説明は割愛します。
executeメソッドを使うと生のSQLが使えるようになります。
ここでのポイントはdownメソッドです。
create_table,add_index,add_columnなどのグループはマイグレーションが進む処理だけでなく、ロールバックする処理もしてくれます。
こちらが意識しなくても、ロールバックの処理が書いてあったわけです。
しかし、upメソッドはマイグレーションを進めるだけです。
必ずdownメソッドで戻る処理も書いておきましょう。
テーブルの削除など効果が取り消せないマイグレーションは

def down
raise Activerecord::IrreversibleMigration
end

として、例外Activerecord::IrreversibleMigrationを発生させましょう。

rails aborted!
StandardError: An error has occurred, all later migrations canceled:
ActiveRecord::IrreversibleMigration

参考文献

Ruby on Rails 6 実践ガイド

 最後に
私がブログを書く目的は、素晴らしい本や、素晴らしい方々の技術記事を知って頂きたいからです。ぜひ、上記の参考文献を見て下さい。(noteなので広告とかは一切ありません。)

現在、株式会社grabssに行くために最後の悪あがきをしています!!
現在の進行状況
この記事は31件目の投稿。目標まで後19件。

よろしければ、スキボタン及びサポートお願いします。勉強の励みになります。

この記事が気に入ったらサポートをしてみませんか?