【问题标题】:Rails strong parameters - Request allowed without required keyRails 强参数 - 允许请求而无需密钥
【发布时间】:2020-01-02 23:24:02
【问题描述】:

我正在开发 Rails API,并且在控制器中使用强参数。我有一个请求规范,它在一个模型上失败,但在所有其他模型上都有效。每个模型的控制器几乎都相同。

正如您在规范中看到的那样,请求正文应该是{ "tag": { "name": "a good name" }}。然而,这个规范使用了{ "name": "a good name" },它应该是无效的,因为它缺少“标签”键。相同控制器功能的相同规范适用于许多其他型号。

另一个有趣的转折是,如果我将控制器的强参数更改为params.require(:not_tag).permit(:name),它会因为不包含“not_tag”键而引发错误。

  • 红宝石:2.6.5p114
  • 导轨:6.0.1
  • 预期响应状态:422
  • 收到响应状态:201

控制器

class TagsController < ApplicationController
  before_action :set_tag, only: [:show, :update, :destroy]

  # Other methods...

  # POST /tags
  def create
    @tag = Tag.new(tag_params)

    if @tag.save
      render "tags/show", status: :created
    else
      render json: @tag.errors, status: :unprocessable_entity
    end
  end

  # Other methods...

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_tag
      @tag = Tag.find_by(id: params[:id])
      if !@tag
        object_not_found
      end
    end

    # Only allow a trusted parameter "white list" through.
    def tag_params
      params.require(:tag).permit(:name)
    end

    # render response for objects that aren't found
    def object_not_found
      render :json => {:error => "404 not found"}.to_json, status: :not_found
    end
end

请求规范

require 'rails_helper'
include AuthHelper
include Requests::JsonHelpers

RSpec.describe "Tags", type: :request do
  before(:context) do
    @user = create(:admin)
    @headers = AuthHelper.authenticated_header(@user)
  end

  # A bunch of other specs...

  describe "POST /api/tags" do
    context "while authenticated" do
      it "fails to create a tag from malformed body with 422 status" do
        malformed_body = { "name": "malformed" }.to_json
        post "/api/tags", params: malformed_body, headers: @headers
        expect(response).to have_http_status(422)
        expect(Tag.all.length).to eq 0
      end
    end
  end

# A bunch of other specs...

  after(:context) do
    @user.destroy
    @headers = nil
  end
end

【问题讨论】:

    标签: ruby-on-rails rspec strong-parameters


    【解决方案1】:

    这种行为是因为 ParamsWrapper 功能在 Rails 6 中默认启用。wrap_parameters 将接收到的参数包装到嵌套哈希中。因此,这允许客户端发送请求而无需在根元素中嵌套数据。

    例如,在一个名为Tag的模型中,它基本上可以转换

    {
      name: "Some name",
      age: "Some age"
    }
    

    {
      tag:
        {
          name: "Some name",
          age: "Some age"
        }
    }
    

    但是,正如您在测试中看到的那样,如果您将所需的密钥更改为 not_tag,包装会按预期中断 API 调用。

    可以使用config/initializers/wrap_parameters.rb 文件更改此配置。在该文件中,您可以将 wrap_parameters format: [:json] 设置为 wrap_parameters format: [] 以禁止此类参数包装。

    【讨论】:

    • 这正是问题所在。无论出于何种原因,我都认为强参数取代了参数包装。但这在技术上甚至没有意义。更糟糕的是,因为所有其他控制器的相同规范都写错了,所以真正引起了混乱。所以他们通过了,即使他们不应该通过。
    猜你喜欢
    • 2015-12-13
    • 1970-01-01
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多