環境
rails: 6.0.3.6
ruby: 2.6.5
結論
errors.instance_values["base"]
を用いることで、対象のインスタンスを取得することができる。
背景
localeが使われていないプロダクトで、localeを少しづつ導入を進めていた。
localeが使われていないので、model内で、バリデーションメッセージを全て手入力で入れていた。
validate: name, present: {message: 'hogeを入力してください'}
そのため、slimのrailsフォームのエラーメッセージを表示する共通テンプレートの中で、エラーメッセージを出力するロジックが以下のように書かれていた。
- errors.messages.values.each |message| do
p = message
直面したこと
一気にlocaleを反映させるのはビッグコミットになるため、一部機能から順に差し替えていった。
validate: name, present: true
しかし、そうすると、
- errors.messages.values.each |message| do
p = message /'を入力してください'と出てしまう
そのため、「locale対応している場合はfull_messagesを、そうではない場合はmessages」を出すことで対応することに。
このファイルの中で、このモデルがlocal対応しているかどうかを判別して処理を分けようと試みたが、errorsから「どのモデルのエラーなのか」を取得する方法が出てこなかった。
(簡単に取れそうなのに、、!!)
試したこと
console上では
[1] pry(main)> hoge = Hoge.new
[2] pry(main)> hoge.save
[3] pry(main)> hoge.errors
=> #<ActiveModel::Errors:0x00007ff0e2a6cb30
@base=
#<Hoge:0x00007ff0eaaa6738
id: nil,
name: nil>,
@details=
{:name=>[{:error=>:blank}]}]},
@messages={:name=>["を入力してください"]}>
と出ていたが、
hoge.errors.base
-> undefined method `base' for #<ActiveModel::Errors:0x00007ff0e2a6cb30>
あれ、取得できない。
こういう時はrailsに聞くのが一番。
hoge.errors.methods
-> :to_hash,
:full_messages,
:delete,
:to_a,
.
.
:instance_values,
.
.
それっぽいの見つけた!
hoge.errors.instance_values
-> {"base"=>
#<Hoge:0x00007ff0eaaa6738
id: nil,
name: nil>,
"messages"=>{:name=>["を入力してください"]},
"details"=>
{:name=>[{:error=>:blank}]}
hashで中身を返してくれるらしい。
暫定コードとしてはこんなかんじ。
ruby:
error_messages = if I18n.exists?("activerecord.attributes.#{errors.instance_values["base"].class.name.underscore}")
errors.full_messages
else
errors.messages.values
end
- error_messages.values.each |message| do
p = message
早く全てlocale移管したい。