先週に引き続き Rails 移行検証をしていて,既存のテーブルに hash
カラムが存在していると ActiveRecord で ActiveRecord::DangerousAttributeError
が発生する問題を発見した.少し調べてみたので残しておく.正確に言うと hash
だけじゃなくて ActiveRecord::Base
に実装されているメソッド名は基本的にダメっていう理解で正しいと思う.例えば save
もそう.
ActiveRecord::DangerousAttributeError: hash is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name.
検証環境
- Ruby 2.2.3
- Rails 4.2.4
Rails Issue を読んでみた
結論として hash
カラムは ActiveRecord ではサポートしていないということだった.ワークアラウンドとして dangerous_attribute_method?
にモンキーパッチを当てる方法もあるけど,何が起きても知らないよと.
there's no supported way around this behavior. You "could" monkey patch this method but there's no guarantee that you'll end up with working code.
safe_attributes
ActiveRecord::DangerousAttributeError
の問題を解決してくれそうな Gem として safe_attributes
がある.ただし,現在はもう全くメンテナンスされていないし,サポートしてる環境も Ruby 1.9 で止まってるので,今から使うには厳しそうな雰囲気だった.
実際に試してみたけど,単純に ActiveRecord::DangerousAttributeError
を回避できるだけで,実際に hash
カラムの値が取得できるわけではなく,モデルオブジェクトに対する .hash
の値が返ってくるだけだった.
pry(main)> Project.first.hash -4443704500580638528
参考として実装を見てみたところ ActiveRecord::Base
に実装されているメソッドに一致する場合に return
したり,ActiveRecord::DangerousAttributeError
が発生したら rescue
してた.
def define_method_attribute(attr_name) return if (bad_attribute_names.include?(attr_name.to_sym)) super(attr_name) end
def instance_method_already_implemented?(method_name) begin return super(method_name) rescue ActiveRecord::DangerousAttributeError return true end return false end
まとめ
先週書いたエントリーと同じ結論になるけど,Rails に移行するのであれば,変に技術的負債を抱えるのではなくて,事前に解消した方が幸せになれると思う.とは言え,あくまで理想論なので,システムの状況を踏まえて意思決定をしたいなというところ.