Rails 7.2 から ActiveRecord::Core#inspect が id しか出力されなくて困っている
例えば以下のような schema のモデルのオブジェクトを p
や pp
などで出力する場合に Rails 7.2 以前では全カラムの値が出力されていました。
ActiveRecord::Schema.define do
create_table :users, force: true do |t|
t.string :name
t.string :email
t.boolean :active
t.timestamps
end
end
class User < ActiveRecord::Base
end
homu = User.create(name: "homu", email: "homu@@example.com", active: true)
# 各カラムの値が出力される
pp homu
# => #<User:0x00007def9a6bde58
# id: 1,
# name: "homu",
# email: "homu@@example.com",
# active: true,
# created_at: 2024-09-08 02:37:14.044523 UTC,
# updated_at: 2024-09-08 02:37:14.044523 UTC>
しかし Rails 7.2 では以下のように id
カラムの値のみが出力されるようになりました。
homu = User.create(name: "homu", email: "homu@@example.com", active: true)
# id のみが出力される
pp homu
# => #<User:0x000075967c049dd0 id: 1>
これは以下の PR で『 #inspect
#pretty_print
で出力するカラムを制御できるようにした』対応による影響になります。
ActiveRecord::Core.attributes_for_inspect
Rails 7.2 では新しく ActiveRecord::Core.attributes_for_inspect
というメソッドが追加されました。
これは #inspect
や #pretty_print
に含まれるカラムを制御するための機能になります。
#inspect
や #pretty_print
は p
や pp
で出力するときに内部で呼ばれるメソッドになります。
例えば次のようにして #inspect
や #pretty_print
に id
name
email
のみ含まれるように設定することができます。
class User < ActiveRecord::Base
# #inspect で出力したいカラム名を配列で設定する
self.attributes_for_inspect = %w(id name email)
end
homu = User.create(name: "homu", email: "homu@@example.com", active: true)
pp homu
# => #<User:0x000074d8f0c58850 id: 1, name: "homu", email: "homu@@example.com">
また次のように :all
を設定することで『すべてのカラムの値』が #inspect
に含まれます。
class User < ActiveRecord::Base
self.attributes_for_inspect = :all
end
homu = User.create(name: "homu", email: "homu@@example.com", active: true)
pp homu
# => #<User:0x000073170d9113a0
# id: 1,
# name: "homu",
# email: "homu@@example.com",
# active: true,
# created_at: "2024-09-08 11:07:28.004564000 +0000",
# updated_at: "2024-09-08 11:07:28.004564000 +0000">
Rails 7.2 ではこれがデフォルトで attributes_for_inspect = [:id]
で設定されています。
なのでデフォルトでは #inspect
で id
のみが含まれていることになります。
ただし development
test
環境では :all
が設定されているのですべてのカラムが出力されます。
attributes_for_inspect
を設定する
デフォルトの デフォルトの attributes_for_inspect
の設定は configure
で設定することができます。
Rails.application.configure do
active_record.attributes_for_inspect = :all
end
もしくは ActiveRecord だけの場合であれば次のようにしても設定できます。
ActiveRecord::Base.attributes_for_inspect = :all
development
test
環境以外でも全部のカラムの値を出力したい場合はこれで対応できます。
所感
正直なところ ActiveRecord::Core.attributes_for_inspect
自体はよい機能だと思うんですが(秘匿したい値をカジュアルに出力されないようにする、みたいニーズはある)デフォルトで id
しか出力されないのはやり過ぎだと思いますね。
#inspect
で出力したいケースってデバッグ目的でデータを参照したり保存したりすることが多いと思うんですが id
だけ出力されたところで全く意味をなさないですよね。
一応 development
test
環境だとデフォルトで :all
が設定されているので挙動が変わらないらしいんですが、逆にそれ以外の環境で差異がでてしまうことによって CI で挙動が担保できなかったりとか、そもそも #inspect
がログ出力とかに依存している場合は全部壊れてしまいます。
なので結局全部 :all
にするのであればデフォルトを [:id]
にする必要性がないと思います(そもそもパフォーマンス的に問題があるのであれば #inspect
をどうにかするのではなくてその処理自体で対応してほしい……。
最初にも書いたんですが #inspect
の出力がやや冗長にあることとかはままあるので、それを制御するために ActiveRecord::Core#attributes_for_inspect
を利用したりできるのはめっちゃいいと思うのでデフォルトを id
だけにするのはやめてほしいなあ…。
おまけ:特定のカラムのみ除外する
attributes_for_inspect
は『特定のカラムのみ指定する』なんですが次のようにすれば『特定のカラムを除外する』こともできます。
class User < ActiveRecord::Base
# attribute_names は全カラム名を返すのでそこから不要なカラムを引く
self.attributes_for_inspect = attribute_names - %w(created_at updated_at)
end
homu = User.create(name: "homu", email: "homu@@example.com", active: true)
pp homu
# => #<User:0x000072c2db9f5f68
# id: 1,
# name: "homu",
# email: "homu@@example.com",
# active: true>
Discussion