はじめに
DB で利用しないカラムが発生して、プライベート化するということで他の方が対応していた
コードレビュー時に「ほんとにこれでいいの?」と思ったので検証および問題点の対応策を考えてみました
ActiveRecord のカラムについて
ActiveRecord
は、Ruby on Rails
の一部であり、
オブジェクト指向型データベースマッピングの実装を提供します
ActiveRecord
を使用すると、
データベーステーブルの行が Ruby オブジェクトとして扱われます
ActiveRecord
モデルのカラムには、
通常public
アクセス権が与えられており、どの部分からでもアクセスすることができます
他の方の対応内容
ActiveRecord
では、モデルクラスの各カラムには通常、
自動的にアクセサメソッドが定義されます
しかし、その中にはDB
上で利用しなくなってしまったカラムが含まれる場合があります
このような場合、アクセサメソッドをprivate
にすることで、
予期せぬ変更が加えられるのを防止することができます
検索してもこのような内容が多くでてきます
class Sample < ApplicationRecord
private
attr_accessor :unused_column
end
問題点
attr_accessor
をprivate
にしても、クラス外からはアクセスできませんが、
ハッシュ構造でアクセスする場合はprivate
化が効果を発揮しません。
class Sample < ApplicationRecord
private
attr_accessor :unused_column
end
sample = Sample.new()
sample.unused_column = "foo" # => NoMethodError (private method `unused_column=' called for #<Sample:0x00007fd0cc104e10>)
sample[:unused_column] = "foo"
解決策
hash アクセスを禁止する
[]=
メソッドをオーバーライドして、ハッシュアクセス自体を禁止することで、
private
なカラムを保護することができます。
class Sample < ApplicationRecord
private
attr_accessor :unused_column
def []=(key, value)
raise 'Hash access is not allowed' if key == :unused_column
super
end
end
影響範囲
テストコードのデータ生成にFactoryBot
を使用している場合には影響があります
FactoryBot
ではcreate
時にunused_column=
のメソッドが呼び出されるため、
別の方法を使用する必要があります
例えば、以下のようにtrait
を定義することで、
create
時にunused_column
に値を設定することができます
class Sample < ApplicationRecord
def []=(key, value)
raise 'Hash access is not allowed' if key == :unused_column
super
end
private
attr_accessor :unused_column
end
FactoryBot.define do
factory :sample do
trait 'unused_column_foo' do
before(:build) do |sample|
sample.send('unused_column=', 'foo')
end
end
end
end
以下のようにcreate
メソッドを使用してサンプルオブジェクトを作成することができます
sample = FactoryBot.create(:sample, :unused_column_foo)
おわりに
Rails
におけるActiveRecord
カラムのプライベート化についてまとめてみました
これによって、モデルのカラムを適切に保護し予期しない変更を防ぐことができます
色々な事情でDBの構造の変更が難しいケースの場合の参考になれば