Rails用于无限可嵌套模型的强参数

时间:2017-11-15 14:36:45

标签: ruby-on-rails strong-parameters

我有一个带有子类QueryGroup的模型QueryElement。 QueryGroup可以包含嵌套的QueryElements。

Say QueryGroup有一个属性名,而QueryElement有一个属性过滤器(仅作为例)

因此,对于强参数,我有类似的东西:

params.fetch(:query).permit(:name, :filter, :query_elements => [:name, :filter, :query_elements => [...]

等等。

我可以允许所有(破坏强参数的安全性,我宁愿避免),或者手动遍历树,这要慢得多。这是我目前的做法。

有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

这样的事情:

REQUIRED = %i( name ).freeze
ALLOWED = (%i( filter query_elements ) + REQUIRED).freeze
MAX_DEPTH = 5

def ensure_params(hash, nest_level = 0) # ah I never come up with good names...
  raise 'you went too deep man' if nest_level > MAX_DEPTH
  hash.fetch_values(*REQUIRED)
  hash[:query_elements] = ensure_params(hash[:query_elements], nest_level + 1) if hash[:query_elements]
  hash.slice(*ALLOWED)
end

在IRB:

> ensure_params({ :filter => 2, :name => 'test', unpermitted_param: :something, :query_elements => { filter: 3, name: 'test', nested_unpermitted: 13 } })
# => {:filter=>2, :query_elements=>{:filter=>3, :name=>"test"}, :name=>"test"} 
> ensure_params({ name: 1, query_elements: { notname: 1 } })
KeyError: key not found: :name
> MAX_DEPTH = 3
# => 3 
> ensure_params({ name: 1, query_elements: { name: 1, query_elements: { name: 1, query_elements: { name: 1, query_elements: { name: 1, query_elements: { name: 1 } } } } }})
RuntimeError: you went too deep man

可能会有一些改进,比如将密钥转换为符号,有更好的错误消息告诉你哪个嵌套级别有丢失的密钥等等。