Rails 4强参数,包含多个对象和整数键

时间:2015-08-11 14:48:49

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

我一次提交一个包含2-4个对象的表单,具体取决于父项的数量。我意识到这可能是非常规的,但我真的希望用户能够在一个表单上一次编辑所有对象。在我的表格上,我正在做:

<%= simple_fields_for "derps[]", derp do |f| %>

<% end %>

然后我在控制器中执行此操作:

def update
  @derps = []
  @rejects = []
  derps_params.each do |key, hash|
    derp = Derp.find(key)
    derp.assign_attributes(hash)
    @rejects << derp unless derp.save
  end
  if @rejects.empty?
    redirect_to @parent, flash: {success: 'Derps were successfully updated.'}
  else
    @derps = @rejects
    render :edit
  end
end

让我们说有两个对象 - 参数通过:

"derps"=>{"1"=>{"attribute"=>"39", "another_attribute"=>"serp", "a_third_attribute"=>"yerp"}, "2"=>{"attribute"=>"30", "another_attribute"=>"49", }}

我在Rails 3中工作时没有强大的参数。我正在升级到rails 4,我正在努力解决这个问题 - 我不断得到“未经许可的参数:1,2”

我假设我需要做类似的事情:

def mashes_params
  params.require(:derps).permit(
  id: []

def mashes_params
  params.require(:derps).permit(
  :id, 

这些方面的东西,但我已经尝试过每一个我能想到没有运气的方式。

这里有什么想法吗?

5 个答案:

答案 0 :(得分:4)

我发现命令行对于在Rails 4中调试强参数非常有帮助。这是我在控制台中测试你的问题的方法:

<!-- Tomcat 7: -->
<Context allowLinking="true" />

<!-- Tomcat 8: -->
<Context>
  <Resources allowLinking="true" />
</Context>

希望借助此工具,您将能够调试我的答案所提供的任何内容,而不是试验和错误。

答案 1 :(得分:1)

最终编辑(希望如此):

必须从头开始重新考虑这一点。我得出结论:因为:id作为通配符,但不允许作为哈希的键,为什么不总是使键1-4,所以我可以明确地将它们列入白名单,然后从键中获取ID-哈希中的值,就像传统的表单嵌套一样?多数民众赞成我最终如何解决它。这是我工作的最终实现:

<% i = @parent.derps.index(derp) + 1 %>
<%= simple_fields_for "derps[#{i}]", derp do |f| %>
  <%= f.hidden_field :id, value: derp.id %>
  <%= render "rest_of_the_fields" %>
<% end %>

然后在控制器中:

def update
  @derps = []
  @rejects = []
  derp_params.each do |key, hash|
    derp = Derp.find(hash.delete("id"))
    derp.assign_attributes(hash)
    @rejects << derp unless derp.save
  end
  if @rejects.empty?
    redirect_to @parent, flash: {success: "Derps updated successfully."} 
  else
    @derps = @rejects
    render :edit
  end
end

然后是强大的参数:

def derp_params
  p = [:id, :attribute_1, :another_attribute, ...]
  params.require(:derps).permit(
    "1" => p, "2" => p, "3" => p, "4" => p
  )
end

呼。希望这有助于某人。

答案 2 :(得分:0)

我见过的绝对最佳解决方案是here

def product_params
  properties_keys = params[:product].try(:fetch, :properties, {}).keys
  params.require(:product).permit(:title, :description, properties: properties_keys)
end

由于我的property_keys有更多嵌套键和值,我再做了一次更改来遍历未命名的键:

response_keys = params[:survey][:responses].try(:fetch, :properties, {}).keys
params.require(:survey).permit(responses: response_keys.map {|rk| [rk => [:question_id, :answer_id, :value]]})

答案 3 :(得分:0)

这是我当前正在使用的方法。您可以像这样逐个允许每个嵌套参数:

params = ActionController::Parameters.new(
  "derps" => {
    "1" => {
      "attribute" => "39",
      "another_attribute" => "serp",
      "a_third_attribute" => "yerp"
    },
    "2" => {
      "attribute" => "30",
      "another_attribute" => "49"
    }
  }
)
# => <ActionController::Parameters {"derps"=>{"1"=>{"attribute"=>"39", "another_attribute"=>"serp", "a_third_attribute"=>"yerp"}, "2"=>{"attribute"=>"30", "another_attribute"=>"49"}}} permitted: false>

params.fetch(:derps).map do |i, attrs|
  [
    i,
    ActionController::Parameters.new(attrs).permit(
      :attribute,
      :another_attribute,
      :a_third_attribute,
    )
  ]
end.to_h.with_indifferent_access
#=> {"1"=><ActionController::Parameters {"attribute"=>"39", "another_attribute"=>"serp", "a_third_attribute"=>"yerp"} permitted: true>, "2"=><ActionController::Parameters {"attribute"=>"30", "another_attribute"=>"49"} permitted: true>}

答案 4 :(得分:0)

这是一种基于 Greg Blass 以上答案的肮脏方式来实现这一点

这可以处理无限数量的带有嵌套参数的索引

def foo_bar_params
   num_keys = params[:foo_bars].keys.size
   the_params = [:id, :attr1, :attr2, :another]
   permit_hash = {}
   i = 0
   while i < num_entries
     permit_hash[i.to_s] = the_params
     i += 1
   end
   params.require(:foo_bars).permit(permit_hash)
end

我确信有一种更好的方法可以做到这一点,但这种方法是可读的,我可以很容易地知道发生了什么......而且最重要的是它有效