Rails 5.1 - JSON 参数是允许的,但在日志中仍显示为不允许

Rails 5.1 - JSON parameter is permitted but still prints as unpermitted in the log

在 Rails 4 here is the question 中关于如何做到这一点。我想知道的是,虽然这有效,但为什么日志仍然报错?

在 Rails 5.1.3 中,我有一个 JSON 列 (letterhead) 作为我的模型属性之一(在 json 里面是一个散列与各种我不关心白名单的属性)。我只想 permit/whitelist 专栏本身。

Rails5.1.4

注意事项

在 5.1.4 中有一个 Rails 方法可以做到这一点,请参阅 this commit。 在 github 上对此进行了相当长的讨论 here。在 Rails 5.1.4 中就是这样:

def account_params
  params.require(:account).permit(:id, :name, :plan_id, letterhead: {})
end

允许:letterhead参数,日志中没有错误显示,模型保存。但显然它允许在该参数内任意输入,因此谨慎使用。

如果你确实想限制在这样的参数中允许使用哪些散列键,那么你也可以将它们列入白名单,例如:

def account_params
  params.require(:account).permit(:id, :name, :plan_id, letterhead: [:address, :logo, :contact_info])
end

这现在可以防止 :letterhead 内的任何其他任意键,因为我明确只允许这 3 个 - :address, :logo, :contact_info

Rails 5.1.3(及更早版本)

我可以使用以下任一方法允许此专栏(也请参阅链接讨论以了解其他可能的选项):

选项 1

def account_params
  params.require(:account).permit(:id, :name, :plan_id, :letterhead).tap do |whitelisted|
    whitelisted[:letterhead] = params[:account].fetch(:letterhead, ActionController::Parameters.new).permit!
  end
end

选项 2

def account_params
  params.require(:account).permit(:id, :name, :plan_id, :letterhead).tap do |whitelisted|
    whitelisted[:letterhead] = params[:account][:letterhead].permit!
  end
end

在这两种情况下,模型都保存了,但在日志中它仍然显示 "unpermitted parameters :letterhead"

  1. 为什么明明允许了还这么说?

  2. 另外,方案一和方案二有什么区别吗?

编辑

数据是这样的:

{"id"=>"a61151b8-deed-4efa-8cad-da1b143196c9", 
"plan_id"=>"1dc49acf-3111-4030-aea1-7db259b53a51", 
"name"=>"Test Account 1", 
"is_active"=>true, 
"letterhead"=>{"left"=>"", "center"=>"", "right"=>""}, 
"created_by"=>nil, 
"updated_by"=>nil, 
"created_at"=>"2017-10-14T19:05:40.197Z", 
"updated_at"=>"2017-10-20T15:14:08.194Z"}

为什么我已经明确允许了,还这么说?

日志来自#unpermitted_parameters! which is called by #permit。所有这一切都发生在 调用 #tap.

之前

选项 1 和选项 2 之间有什么真正的区别吗?

区别归结为

params[:account].fetch(:letterhead, ActionController::Parameters.new).permit!

params[:account][:letterhead].permit!

如果 :letterhead 未通过,后者将导致 NoMethodError,因为 params[:account][:letterhead] 将 return nil。前者 return 是参数的空散列。