備忘録的な内容なので参考までに。
設定の設置場所はconfig/initializers/error_customize.rb
ActionView::Base.field_error_proc = proc do |html_tag, instance|
if instance.is_a?(ActionView::Helpers::Tags::Label)
html_tag
else
method_name = instance.instance_variable_get(:@method_name)
errors = instance.object.errors[method_name]
view = ActionView::Base.new
field_tag = []
field_tag << html_tag
field_tag += errors.map do |error|
view.content_tag(:div, class: "help-block") do
"#{instance.object.class.human_attribute_name(method_name)}#{error}"
end
end
view.content_tag(:div, class: "has-error") do
view.safe_join(field_tag)
end
end
end
参考にしたQiita記事: https://qiita.com/zaru/items/54cd20520feda61f5332
自分で手を加えたポイント
このままだと、ただ参考にした記事をパクッてるだけやん、となりそうなので上記の記事を参考に自分なりに修正を加えた箇所について解説をします。
ActionView::Base.field_error_proc = proc do |html_tag, instance|
if instance.is_a?(ActionView::Helpers::Tags::Label)
html_tag
最初のif文のところで、html_tag.html_safe
という記載にhtml_tag
に書き換えました。理由は、私のRubocop先生からRuboCop::Cop::Rails::OutputSafety
の指摘を喰らったため。ただし、単純にhtml_safe
を外しただけでは根本解決になっていのでは?という疑問を持たれそうなので一応補足をすると、pryで覗いたときにこんな感じの挙動をしていることがわかりました。
はい、もともとActiveSupport::SafeBuffer
クラスのインスタンスなのでhtml_safe
は不要なんですね。ということで削除しても問題なさそうということがわかったので削除しました。
else
method_name = instance.instance_variable_get(:@method_name)
errors = instance.object.errors[method_name]
view = ActionView::Base.new
field_tag = []
field_tag << html_tag
field_tag += errors.map do |error|
view.content_tag(:div, class: "help-block") do
"#{instance.object.class.human_attribute_name(method_name)}#{error}"
end
end
view.content_tag(:div, class: "has-error") do
view.safe_join(field_tag)
end
end
後半のelse文のところについては、ごっそりと書き方を変えています。ポイントは2つ。
1つ目は、こちらも同じくrubocop先生からRuboCop::Cop::Rails::OutputSafety
の指摘を喰らっていたので、RuboCop::Cop::Rails::OutputSafety
のGoodパターンであるsafe_join
にて最終的にHTMLを吐き出す流れを取った点です。
2つ目は、元のコードの場合、発生しているバリデーションエラーの内、最初のエラーのみしか取れないロジックになっていたので、errors.each
のところですべてのエラーをHTMLとして吐き出す処理を加えた点です。
まとめ
これで根本的なバグ(最初のエラーしか取れないバグ)は解決し、Rubocop先生からも指摘をされないコードになりました。この設定自体はかなり便利な設定だなぁと思うので、興味がある方はぜひ使ってみてください。大本のロジックについては自分で考えることができなかったので参考にさせて頂いた記事には感謝です。