なんじゃくにっき

プログラミングの話題中心。

Railsのviewで部分テンプレート(partial template)内でエラーが起きた時に画面全体がエラーになるのを防ぐ(1)

やりたいこと

Railsのviewで部分テンプレート内でエラーが起きたときに画面全体がエラーになるのを防ぎたい

想定しているケースは

  • ヘッダやフッタの描画やscriptタグの埋め込み時にエラーが発生するパターン
  • データ欠損だったりの場合が意図せず発生して本来nilを想定していない場所がnilになったり、考慮漏れでnilになったり

方法

Helper側

こういうHelperを用意します。

(error_boundaryって名前はreactのパクリ)

app/helpers/application_helper.rb

module ApplicationHelper

  def error_boundary
    yield
  rescue => ex
    puts ex
    # TODO: 適宜エラートラッキングツールに通知するなり、ログを吐くなりする
  end
end

Template

テンプレート側はこんな感じ

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <header>
      <% error_boundary do %>
        <div>
          <%= 1 / 0 %>
          ヘッダ
        </div>
      <% end %>
    </header>

    <main>
      <%= yield %>
    </main>
  </body>
</html>

header内でゼロ除算が起きると、通常ならページ全体がエラーになりますが、

error_boundaryで囲むと例外がキャッチャされて、headerの描画が途中で止まりますが、ページ全体がエラーになることはなく、yield部分が描画されます。

注意点

エラーは通知しよう

エラーをrescue節でキャッチしたあと通知せずに握りつぶすとエラーに気づかないままになってしまいます。

何らかの手段で通知して気付けるようにしましょう。

描画が途中で止まります

このやり方だと描画が途中で止まります。

<% error_boundary do %>
  <div>
    <%= 1 / 0 %>
    ヘッダ
  </div>
<% end %>

だと、"ヘッダ"という文字列が描画されませんが、

<% error_boundary do %>
  <div>
    ヘッダ
    <%= 1 / 0 %>
  </div>
<% end %>

だとエラーが発生する箇所より前の部分は描画されて”ヘッダ”という文字列が描画されます。

また、閉じタグなしのタグが出力されることがあります。

多少HTMLが壊れても大丈夫なように、error_boundaryはdivかなにかのタグで囲っておいたほうが良いと思います。

main部分のyieldには適用させない方が良さそう

場合によるとは思いますがメインコンテンツがエラーになるようなケースはcatchせずにエラーとしたほうが良いかなと思います。

本来エラーになる場合を200エラーにしてしまわない。

あくまでメインコンテンツ以外の部分がエラーになったときにメインコンテンツまで見えなくなる大事故を防ぐために緊急対応策です。

必ずしも書いた順番に評価されるわけではないのに注意

例えば、yieldをerror_boundaryで囲ったとして、全てのエラーをキャッチできるわけではないです。

yield内の計算は予めまとめて計算してoutput_bufferに格納しておく処理があったりするため。

続き

続きあります

Railsのviewで部分テンプレート(partial template)内でエラーが起きた時に画面全体がエラーになるのを防ぐ(2) - なんじゃくにっき