知らなきゃ実務でヤバイ❗️Railsでカラムの追加と削除の方法(誤ってカラム追加の対処法など実務ベースで解説)
概要
カラムを追加したり削除する機会があると思います。
その際に新たにカラムを変更するためのマイグレーションスクリプトを作成します。
少しややこしいとこなので解説していきます。
カラム追加
まずカラムの追加方法からです。以下のコマンドを使ってマイグレーションファイルを作成します。
rails generate migration AddColumnNameToTableName column_name:data_type
実際の例を出して見てきます。
rails generate migration AddEmailToUsers email:string
するとdb/migrate/YYYYMMDDHHMMSS_add_email_to_users.rb
のファイルができます。
class AddEmailToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :email, :string
end
end
その後マイグレーションを実行します。
rails db:migrate
カラム削除
カラムの削除方法をお伝えしていきます。マイグレーションファイルの作成のやり方です。
rails generate migration RemoveColumnNameFromTableName column_name:data_type
今回はDailyReportモデルのtimestampsのカラムの削除方法です。
rails generate migration RemoveTimestampsFromDailyReport timestamps:datetime
このコマンドを実行すると以下のファイルができました。db/migrate/YYYYMMDDHHMMSS_remove_timestamps_from_daily_report.rb
のようなファイルができるはずです。
class RemoveTimestampsFromDailyReport < ActiveRecord::Migration[7.0]
def change
remove_column :daily_reports, :timestamps, :datetime
end
end
カラムの削除コマンドを使うと以下の削除用のマイグレーションファイルができます。
class RemoveColumnNameFromTableName < ActiveRecord::Migration[6.0]
def change
remove_column :table_name, :column_name, :data_type
end
end
その後にマイグレーションを実行します。
rails db:migrate
実務でどう使ったか
実際に実務でこんなようなことがありました。
curlでAPIにデータを取得すると
id: 1,
user_id: 1,
timestamps: null,
deleted_at: nil,
created_at: 〇〇,
updated_at: 〇〇,
みたいなデータがありました。timestampsがnullになっているのがおかしかったので、
これをカラムから削除しました。
自分は最初上の削除のやり方でカラムを削除しました。するとこんなレビューをもらいました。
「まだ本番環境で公開していないのでuserのmigrationのようにrollbackをして削除でOKでいいですよ!」
というレビューでした。
rails db:rollback
はDBのマイグレーションを一つ前の状態に戻すためのコマンドで、DBのスキーマ変更や
テーブルの作成、削除などの操作を実行するために使われます。
これで不要なカラムが削除されました。
リリースした環境でrollbackはNG❗️
リリース済みの環境でDBのカラムを削除する場合、rails db:rollback
を使用することは通常避けるべきです。以下はその理由です:
-
データの損失
カラムを削除すると、そのカラムに関連するデータが消える場合があり、
本番環境ではすでに多くのデータがあるため、データの損失になりかねません。
2.データベースの一貫性が無くなる
アプリケーションのコードが削除したカラムを参照している時、それを削除することでエラーが発生する可能性があります。
3.デプロイの複雑性
ロールバックは通常、開発やテスト環境での使います。
本番環境ではすでに多くのユーザーが利用しているため、デプロイの途中で予期せぬ問題が発生する可能性があり、サービスが落ちてしまう可能性があります。
リリースした環境でrollbackを使ったケース
実務でユーザーが〇〇の購入日(最初に購入した日)を画面に表示させるタスクを任されました。
〇〇モデルにpurchase_dateカラムを追加しました。(上のrailsコマンドでカラムを追加)
しかし、purchase_dateカラムを追加せずとも、created_atが購入日という指摘をもらいました。
直接migrate(年日付_add_〇〇_to_〇〇.rbみたいなファイル)を直接削除してしまうと、
カラムがDB上に残ってしまうので、違うやり方でやることにしました。
(すでに rails db:migrateは実行していた)
なので、まずは以下のコマンドでmigrationの状況を確認します。
rails db:migrate:status
#中略
up 年月日 Add 〇〇 to 〇〇
up 年月日 Add 〇〇 to 〇〇
up 年月日 Add 〇〇 to 〇〇
up 20240206152613 Add purchase date to 〇〇
この状態だと、カラムがmigrationに反映された状態です。1番下に表示されていて、
最新版でした。そこでrollbackを使って前の状態に戻します。
rails db:rollback
再度以下のコマンドを実行します。
rails db:migrate:status
#中略
up 年月日 Add 〇〇 to 〇〇
up 年月日 Add 〇〇 to 〇〇
up 年月日 Add 〇〇 to 〇〇
up 20240206152613 Add purchase date to 〇〇
これでpurchase_dateカラムはmigrationに反映されなくなりました。
rollback補足
上のrollbackは1つ前のrollbackですが、下のコマンドは2つ前と3つ前のrollbackです。
STEP=を使うとこが違うとこです。
rails db:rollback STEP=2
rails db:rollback STEP=3
null falseの追加
マイグレーションが以下のようにnull falseがない状態になってしまいました。
その際に、null falseを追加しました。
class CreateArticles < ActiveRecord::Migration[7.0]
def change
create_table :articles do |t|
t.string :title,null false
t.text :content,null false
t.references :user, null: false, foreign_key: true
t.timestamps
end
end
end
- 補足
null falseは記事にタイトルと文章がnull(タイトルと文章を書かないといけない)になってはいけない設定です。
修正後マイグレーションを実行します。
rails db:migrate
実行後コンソールに入ります。
$ rails c
以下のようなコマンドで、falseが出たら設定ができたということです。
Article.columns_hash["title"].null # => false
Article.columns_hash["content"].null # => false
- schema.rbを確認
ここで設定されていたらOKです。
ActiveRecord::Schema[7.0].define(version: 2024_07_19_152440) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "articles", force: :cascade do |t|
t.string "title", null: false
t.text "content", null: false
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_articles_on_user_id"
end
資料
Discussion