25
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

稼働中RailsアプリのDBに対してカラム追加・削除する

Last updated at Posted at 2018-06-12

前提

usersのテーブル定義は以下の状態でサービス稼働中

user.rb
class User < ActiveRecord::Base
end

$ User.column_names
# => ["id", "name", "created_at", "updated_at"]

ここにカラムemailを追加すると起きる問題

1. プリペアドステートメントでエラー

以下の記事より

アプリケーションが動作しているプロセス以外からRDBに定義の変更を加えると、トランザクション内部でプリペアドステートメントが発生する場合にエラーになります。

ActiveRecord::PreparedStatementCacheExpired: ERROR: cached plan must not change result type


>PostgreSQLの場合、テーブルに定義的な変更が加わった場合、プリペアドステートメントの再作成を必須としています。

## 2. modelのschema cacheでエラー
ActiveRecordでは`ApplicationRecord`クラスを継承したmodelはrailsがDBのschema情報から、アクセサメソッドなどを追加してくれるのですが、model毎に初回テーブルアクセス時にschema情報をキャッシュしています。
その為、キャッシュしているschema情報と実際のschemaに差分があるとエラーが発生します。
例えば以下は、稼働中に`email`カラムを増やし、cacheが残ったままアクセスした場合に発生します。

ActiveModel::UnknownAttributeError: unknown attribute 'email' for User.


# 対策

## Rails5以降

`ActiveRecord::Base.ignored_columns`で`email`カラムをActive Recordに対して隠蔽する。

```ruby:user.rb
class User < ApplicationRecord
  self.ignored_columns = %w(email)
end

$ User.column_names
# => ["id", "name", "created_at", "updated_at"]

Rails4

ActiveRecord::Base.columnsをオーバーライドしてemailを読み込ませないようにする。

user.rb
class User < ActiveRecord::Base
  def self.columns
    super.reject {|column| column.name == 'email'}
  end
end

$ User.column_names
# => ["id", "name", "created_at", "updated_at"]

to_jsonを使う場合

to_jsonを使用する時は上記では対策できずエラーになるのでexceptオプションを使用します。

$ JSON.parse(User.all.to_json).first.keys
# => SystemStackError: stack level too deep

$ JSON.parse(User.all.to_json(except: [:email])).first.keys
# => ["id", "name", "created_at", "updated_at"]

参考

https://eagletmt.hateblo.jp/entry/2017/09/24/004709
http://48n.jp/blog/2017/03/06/ignored-columns-rails5/
https://qiita.com/hirokishirai/items/d2374324c8c7d265363f

25
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?