强参数允许所有嵌套属性的属性。

36

strong parameters中,有没有一种方法可以允许嵌套属性模型的所有属性?以下是一个示例代码。

class Lever < ActiveRecord::Base
 has_one :lever_benefit
 accepts_nested_attributes_for :lever_benefit
end

class LeverBenefit < ActiveRecord::Base
  # == Schema Information
  #  id          :integer          not null, primary key
  #  lever_id    :integer
  #  explanation :text
end

对于强参数,我目前正在编写以下内容

def lever
 params.require(:lever).permit(:name,:lever_benefit_attributes => [:lever_id, :explanation])
end

有没有一种方法可以写入嵌套属性,允许所有属性而不明确给出属性名称,例如lever_id和explanation?

注意:请不要将此问题与permit!permit(:all)混淆,这是用于允许嵌套属性的全部。


尝试阅读这个答案,也许会有帮助。> https://dev59.com/hmYq5IYBdhLWcg3wcgLq - Sachin Singh
谢谢,但我已经看过了。如果你注意到它正在执行选择性属性过滤的相同操作(assets_attributes: :filename),这是传递文件名的。我想允许嵌套属性的所有参数。 - AnkitG
6个回答

59

在我遇到的情况中,只有在写入序列化列时允许嵌套参数哈希中任意键似乎是合理的。我已经成功地处理了它:

class Post
  serialize :options, JSON
end

class PostsController < ApplicationController
  ...

  def post_params
    all_options = params.require(:post)[:options].try(:permit!)
    params.require(:post).permit(:title).merge(:options => all_options)
  end
end

try 确保我们不需要一个 :options 键的存在。


非常感谢,你节省了我很多时间 :) - Jigar Bhatt
2
这是正确的答案!你应该得到一个绿色的复选框! - Blair Anderson
2
为什么要使用params.require(:post).fetch(:options, nil)而不是params.require(:post)[:options] - Patrick Brinich-Langlois
@PatrickBrinich-Langlois 也记不得 fetch 是从哪里来的了。已更新答案。 - tfischbach

21

我很惊讶没有人提出这个想法:

params.require(:lever).permit(:name,:lever_benefit_attributes => {})

它允许在“lever_benefit_attributes”哈希中任何属性。对我来说有效。 - Ian Vaughan
1
三个小时和许多头痛之后,我也感到惊讶。这对于我的jsonb列来说非常完美,可以在devise_parameter_sanitizer中使用。 - Alberto T.
我有一个带有3层嵌套数组的参数,其中包含动态值,这允许一切。非常感谢! - Rob Carpenter

17
实际上,有一种方法可以仅将所有嵌套参数列入白名单。
params.require(:lever).permit(:name).tap do |whitelisted|
  whitelisted[:lever_benefit_attributes ] = params[:lever][:lever_benefit_attributes ]
end

这种方法比其他解决方案更具优势。它允许允许深度嵌套参数。
而其他解决方案如下:
nested_keys = params.require(:lever).fetch(:lever_benefit_attributes, {}).keys
params.require(:lever).permit(:name,:lever_benefit_attributes => nested_keys)

不要。


来源:

https://github.com/rails/rails/issues/9454#issuecomment-14167664


3
这在Rails 5 中对于深度嵌套的参数不起作用。请在此处查看原因:http://eileencodes.com/posts/actioncontroller-parameters-now-returns-an-object-instead-of-a-hash/ - rmcsharry

12

首先,请确保您真的想要允许嵌套哈希中的所有值。阅读Damien MATHIEU的答案,以了解可能存在的安全漏洞...

如果您仍然需要/希望允许哈希中的所有值(例如为记录存储未结构化的用户提供的元数据等情况下),则可以使用以下代码段来实现:

def lever_params
  nested_keys = params.require(:lever).fetch(:lever_benefit_attributes, {}).keys
  params.require(:lever).permit(:name,:lever_benefit_attributes => nested_keys)
end

注意:这与 tf的答案非常相似,但更加优雅,因为您将不会收到任何Unpermitted parameters: lever_benefit_attributes的警告/错误。


6

尝试

params.require(:lever).permit(:name, leave_benefit_attributes: LeaveBenefit.attribute_names.collect { |att| att.to_sym })

-5
强参数的整个意义在于其名称:使您的输入参数强大。
允许所有参数是一个非常糟糕的想法,因为它会允许任何人插入您不一定希望用户更新的值。

在您提供的示例中,您提到了您目前需要提供的两个参数:
[:lever_id, :explanation]

如果您允许所有参数,那么有人就可以更改任何其他值。
例如created_atlever_id

这肯定是一个安全问题,这就是为什么您不应该这样做的原因。
明确指定所有属性可能看起来很无聊。
但这是保持应用程序安全所必需的。

编辑:对于那些给这个回答点踩的人。也许这不是你们想要的答案,但却是你们需要的答案。
将所有嵌套属性列入白名单是一个巨大的安全漏洞,而强参数正试图保护你免受此类漏洞的侵害,而你正在删除它。
看看是什么导致了构建强参数,并且不使用它会对你产生什么样的影响:https://gist.github.com/peternixey/1978249


1
谢谢,你的回答提出了一个有效的观点,即这可能是一个安全问题。我会明确地提到这些属性。 - AnkitG
30
如果你接收到的哈希值存储在序列化的JSON列中,那么密钥的安全性就没有任何问题(除了输入过大的现有问题)。我有一个这样的用例,我想允许哈希中的任意键。 - Matt Connolly
2
有其他保护属性的方法。例如,抛出未经许可的参数的命令对象是更好的方法,我个人认为。 - Keith Gaddis
15
有些情况下,你可能需要允许使用即席参数,比如一个具有松散或不存在模式的序列化对象。这种情况确实比“从不”经常发生。 - Dave Rapin
5
这是一个不好的回答。Stack Overflow旨在解决问题,而不是告诉人们他们做错了什么。在我看来,这类回答只有在提供了替代方案时才应被视为有效,帮助作者达成目标。例如,可以参考下面的答案。 - Andreas
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接