セキュリティ系の勉強・その他開発メモとか雑談. Twitter, ブログカテゴリ一覧
本ブログはあくまでセキュリティに関する情報共有の一環として作成したものであり,公開されているシステム等に許可なく実行するなど、違法な行為を助長するものではありません.

【Ruby On Rails】ネストとガード節

//

ネストがひどい

下のコードがスマートじゃない。(リダイレクトのパスとかは適当です)

# hoge_controller.rb
  def destroy
    if target = User.find_by(id: params["id"])
      if current_user.unfollow(target) #フォローを外すみたいな動作
        flash[:info] = I18n.t("hoge.destroy.success")
      else
        flash[:danger] = I18n.t("hoge.destroy.failure")
      end
    else
      flash[:danger] = I18n.t("hoge.destroy.user_not_found")
    end  
    redirect_to(root_path)
  end


RuboCop先生曰く、制御構文で条件式のネストは避けましょう。とのこと。ガード節を使います。

ガード節

不正なデータを弾きたいときはガード節を使いましょう。 ガード節とは、できるだけ素早く関数から抜けられるようにと 関数の先頭に置かれている条件文のことです。
https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md#no-nested-conditionals

return ~ unlessを使用して、予期しない条件の場合はこれ以降関係ないっすよ。ってしてあげることで、見た目的にも読みやすくなる気がします。if~elseが適しているものとして、条件分岐に相対性があるものとの噂もあったので、

# hoge_controller.rb
  def destroy
    target = User.find_by(id: params["id"])
    return redirect_to(root_path, flash: { danger: I18n.t("hoge.destroy.user_not_found") }) unless target

    if current_user.unfollow(target)
      flash[:info] = I18n.t("hoge.destroy.success")
    else
      flash[:danger] = I18n.t("hoge.destroy.failure")
    end
    redirect_to(root_path)
  end

余談

上のコードのガード節でfind_by行までまとめて1行で書く場合、

return redirect_to(root_path, flash: { danger: I18n.t("hoge.destroy.user_not_found") }) unless (target = User.find_by(id: params["id"]))

とかけますが、target変数の出どころがわかりにくいので、2行にしてます。また、上記の場合、unlessの条件に()つけないと、RuboCop先生に注意されますが、コード自体は走ります。(==のタイポと思われる)