Techioz Blog

Rails は複数の必須パラメータを宣言します

概要

Rails 7 アプリでは、外部 API からリクエストを受信しています。受信したリクエストが有効かどうかを確認したい。そのためには、強力なパラメータを使用する必要があります。エンドポイントにヒットするサンプル JSON リクエストは次のとおりです。

  "sdd_request": {
    "return_url": "https://example.com/return",
    "data": {
      "debit_method": "CORE",
      "debtor": {
        "name": "John Doe",
        "email": "[email protected]",
        }
      },
      "extension": {
        "signees": [{email: '[email protected]', name: 'joe', last_name: 'smith' }],
        "creditor": {
          "id": "12345",
          "name": "Acme Inc.",
          "address": {
            "city": "New York",
          }
        }
      }
    }
  }

したがって、必要なものは次のとおりです。

- return_url
- data
- signees
- creditor

上記のパラメータを要求するにはどうすればよいですか?

私がやったことは次のとおりです。

  def sdd_setup_request_params
    params.require(:sdd_request).permit(
      :return_url,
      data: [
        :debit_method,
        debtor: [
          :name,
          :email,
          ]
        ],
        extension: [
          signees: [],
          creditor: [
            :id,
            :name,
            address: [
              :city,
            ]
          ]
        ]
      ]
    )
  end

しかし、私が理解しているところによると、たとえば、個別のコンポーネントではなく、sdd_requestのオブジェクト全体が必要です。署名者が欠落していても、パラメータが欠落しているというエラーは発生しませんよね?

解決策

強力なパラメーターの役割は、データを検証することではありません。一括割り当ての脆弱性を回避するためにパラメータをホワイトリストに登録するだけです。

require は、パラメーターの一般的な構造によりリクエストの処理を続行することが無意味になった場合に、早期に回避するために使用されます。たとえば、典型的な Rails コントローラーの場合は次のようになります。

params.require(:person)
      .permit(:name, :age, :city)

キー :person が欠落している場合はリクエストの処理を続行しても意味がないため、ActionController::ParameterMissing 例外が発生し、Rails がレスキューして 400 - Bad Request レスポンスを返します。

これにより、ハッシュを予期していて代わりに nil を取得した場合に発生する可能性のある潜在的な nil エラーが防止されます。

実際の属性の存在を検証するのは、Rails のモデルの仕事です。

class Person
  include ActiveModel::Model
  include ActiveModel::Attributes
  attribute :name
  attribute :age
  attribute :city
  validates :name, :age, :city, presence: true
end

あなたは今こう思っているかもしれません: でも、API から取得して保存していないので、モデルがありません。モデルはアプリケーション内のエンティティを正規化された形式で表すため、永続化がなくても非常に役立ちます。

何らかの理由でどうしてもモデルを避けたい場合は、if ステートメントの Web よりももう少し猶予を持ってコントローラーでモデルレス検証を提供する gem があります。

JSONAPI.org のようなネストされたハッシュ構造で require を使用することはできますが、これは単一のキーを返すだけで、最初に欠落しているキーで発生するため、入力の何が間違っているかについて意味のある詳細なフィードバックを提供するために使用することはできません。

params.require(:data)
      .require(:attributes)
      .permit(:name, :age, :city)