LoginSignup
5
5

More than 5 years have passed since last update.

grapeで「あるパラメータが特定の値の場合のみ、別のパラメータをチェックする」バリデーションを実行する方法

Posted at

Railsとgrapeを使用してWebAPIを作成する。
grapeでは入力パラメータのバリデーションが事細かく用意されているが、なぜか「あるパラメータが 特定の値 の場合のみ、別のパラメータをチェックする」機能がない。そんなにレアケースだろうか?

ちなみに、「あるパラメータが 存在する 場合のみ、別のパラメータをチェックする」機能はある。(givenブロック)

バージョンはRuby(2.2), Rails(4.2), grape(0.13.0)で確認した。

例として、次のようなAPIがあったとする。dish"nigiri"の場合のみamount_of_wasabiをチェックしたい。
与えられる正しい入力は{ "dish": "nigiri", "amount_of_wasabi": "M" }{ "dish": "chirashi" }のような形を想定する。

考え方としては、特定の場合のみvalidatorを追加するのは面倒なので逆に特定の場合のみ外すようにする。

my_api.rb
class MyAPI < Grape::API
  resource :sushi_menus do
    params do
      requires :dish, type: String, allow_blank: false, values: ["nigiri", "chirashi"]
      requires :amount_of_wasabi, type: String, allow_blank: false, values: ["w/o", "S", "M", "L"]
    end

    before_validation do
      # HACK: dishが"nigiri"以外の場合はamount_of_wasabiのvalidatorを外す
      @rejected_validators = []
      unless params[:dish] == "nigiri"
        @rejected_validators = route_setting(:saved_validations).select { |v| v.attrs.include?(:amount_of_wasabi) }
        route_setting(:saved_validations).reject! { |v| v.attrs.include?(:amount_of_wasabi) }
      end
    end

    after_validation do
      # HACK: 外したvalidatorを戻す
      route_setting(:saved_validations).concat(@rejected_validators)
    end     

    post do
      # ...省略
    end
  end
end

これでできることはできるが、あまりにも醜悪なのでAPI設計の方を変えてしまうという手もある。

別解としての設計変更

入力を{ "dish": { "nigiri": { "amount_of_wasabi": "M" } } }{ "dish": { "chirashi": true } }のような形に変更する。

my_api.rb
class MyAPI < Grape::API
  resource :sushi_menus do
    params do
      requires :dish, type: Hash, allow_blank: false do
        optional :nigiri, type: Hash do 
          requires :amount_of_wasabi, type: String, allow_blank: false, values: ["w/o", "S", "M", "L"]
        end

        optional :chirashi, type: Boolean, values: [true]

        exactly_one_of :nigiri, :chirashi
      end
    end

    post do
      # ...省略
    end
  end
end
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5