![見出し画像](https://assets.st-note.com/production/uploads/images/62882609/rectangle_large_type_2_a1c01ab7497f4b90e40a3f10dc669131.jpeg?width=1200)
【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
参考文献
最後に
私がブログを書く目的は、素晴らしい本や、素晴らしい方々の技術記事を知って頂きたいからです。ぜひ、上記の参考文献を見て下さい。(noteなので広告とかは一切ありません。)
現在、株式会社grabssに行くために最後の悪あがきをしています!!
現在の進行状況
この記事は31件目の投稿。目標まで後19件。
よろしければ、スキボタン及びサポートお願いします。勉強の励みになります。
この記事が気に入ったらサポートをしてみませんか?