Railsにおけるカスタム例外の定義方法パターン

Ruby

前回、【Ruby】カスタム例外の作成と利用に関する基礎知識でRubyにおけるカスタム例外の基礎知識について紹介しました。
今回はRailsアプリケーションでカスタム例外を利用する際の定義パターンについて紹介します。

クラス内にカスタム例外のクラスを定義する

あるクラスでしか利用しない独自の例外クラスを定義したい場合や、カスタム例外名の重複を防ぎたい場合に利用されるパターンです。
クラス内にカスタム例外を定義することで名前空間つきのカスタム例外が作成できます。

たとえば、リクエスト元のIPアドレスを制限するモジュールでカスタム例外を利用すると以下のようになります。コードの詳細解説は【Rails】APIリクエストにIPアドレスの制約をつける方法で紹介しています。

app/controllers/concerns/ip_restrictable.rb

module IpRestrictable
  class IpAddressInvalidError < StandardError
    def initialize(address)
      super("許可していないIPアドレスからのリクエスト - IP address=#{address}")
    end
  end

  extend ActiveSupport::Concern

  included do
    before_action :validate_ip_adress
  end

  private

  def validate_ip_adress
    address = request.remote_ip
    raise IpRestrictable::IpAddressInvalidError.new(address) unless allow_ip_addresses.include?(address)
  end

  def allow_ip_addresses
    IPAddr.new(Rails.application.config_for(:ip_address)["allow_api_access"])
  end
end

カスタム例外の定義一覧を記載する独自クラスを用意する

任意のクラスで利用するカスタム例外を定義したい場合に利用されるパターンです。
具体的な利用例は以下の通りです。

config/initilizers/exceptions.rb

class IpAddressInvalidError < StandardError; end

app/controllers/concerns/ip_restrictable.rb

module IpRestrictable
  extend ActiveSupport::Concern

  included do
    before_action :validate_ip_adress
  end

  private

  def validate_ip_adress
    raise IpAddressInvalidError unless allow_ip_addresses.include?(request.remote_ip)
  end

  def allow_ip_addresses
    IPAddr.new(Rails.application.config_for(:ip_address)["allow_api_access"])
  end
end

app/controllers/application_controller.rb

class ApplicationController < ActionController::API
  rescue_from IpAddressInvalidError, with: :render403

  private

  def render403(exception = nil)
    render json: { message: "Invalid Ip Address" }, status: :forbidden
  end
end

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!