エラーメモ【TypeError】

エラーの解決過程を記録しておきます。
記事投稿アプリで記事内容を未入力で投稿しようとすると以下のようなエラーが発生しました。

TypeError - no implicit conversion of nil into String:

TypeErrorとは

メソッドの引数に期待される型ではないオブジェクトや、期待される振る舞いを持たないオブジェクトが渡された時に発生します。

エラー文を翻訳

no implicit conversion of nil into Stringを翻訳すると

nilからStringへの暗黙の変換がない

となりました。
string型に変換する必要がありそうです。

該当箇所を確認

現在の該当箇所のコードは

  def build_body(controller)
    result = ''

    article_blocks.each do |article_block|
      result << if article_block.sentence?
                  sentence = article_block.blockable
                  sentence.body
                end
    end

    result
  end

こんな感じです。
簡単に言うとコンテンツがあれば<<でresultに追加する、というコードです。
コンテンツが存在すれば正常に処理され画面が表示されますが、コンテンツがないままだとエラーが発生する状態です。

string型のオブジェクトを取得したいのにnil型だから受け取れない、とのことなのでまずは実際に何型のオブジェクトか見てみます。

Image from Gyazo

sentence.body.classsentence.bodynil型だと分かりました。
これをstring型にできれば解決するはずです。

どうやって型を変えるか

初めに思いついたのはto_sメソッドでstring型に変換するやり方です。

Image from Gyazo

想定通り、string型になりました。
このやり方でもエラーは解決しましたが、||=を使って空文字を明示する書き方の方が良いそうです。

  def build_body(controller)
    result = ''

    article_blocks.each do |article_block|
      result << if article_block.sentence?
                  sentence = article_block.blockable
                  sentence.body ||= ''
                end
    end

    result
  end

このようにしてエラー解決できました。

||= は何をしているか

||=は自己代入やnilガードと呼ばれるそうです。
左辺がnilまたはfalseの場合は右辺が代入され、それ以外の場合は代入はされません。
sentence.bodyに「テスト」と入力して確認してみます。
入力されているのでnilにはならないはずです。

Image from Gyazo

nil?メソッドでfalseが返ってきたのでsentence.bodyはnilではないことがわかります。
nilではないので右辺の''(空の文字列)は代入されず「テスト」となっていますね。

書籍などで||=この書き方を見たり、nilガードという言葉自体は見たことありましたが、実際に検証して理解が深まりました。

最後に

||= これだけ見ると記号か暗号のようですが、hoge = 1のような変数に代入するコードに||という関所があって、hogeが空っぽの時は1さんに「うむ、入れてやろう」、hogeに何か入ってる時は「今hogeは満員だ。帰れ」と言ってるイメージで覚えました。知らんけど。
今回は以上です。ありがとうございました。

参考サイト

class TypeError (Ruby 3.0.0 リファレンスマニュアル)

Rubyで使われる記号の意味(正規表現の複雑な記号は除く) (Ruby 3.0.0 リファレンスマニュアル)

【Ruby】使いこなせると便利。||演算子のいろんな使い方 - Qiita

Rubyの自己代入(||=)とはこんな仕組みです - Qiita

【Ruby入門】nilのポイントまとめ(nil? empty? blank? present?) | 侍エンジニアブログ

Rubyのnilガードについて調べてみた - Qiita