ruby-on-rails Rails 4 Strong Params多个对象和整数键

jucafojl  于 2023-10-21  发布在  Ruby
关注(0)|答案(6)|浏览(147)

我一次提交一个包含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,

沿着这些线的东西,但我已经尝试了每一种方法,我能想到的运气不好。
有什么想法吗?

dgsult0t

dgsult0t1#

我发现命令行对于在Rails 4中调试强参数非常有帮助。下面是我如何在控制台中测试您的问题:

rails c # From within your project directory, short for 'rails console'

params = ActionController::Parameters.new( { derps: { 1 => { attribute: 39, another_attribute: "serp" }, 2 => { attribute: 30, another_attribute: 49 }  } } )

params # To make sure that the object looks the same

permitted = params.require( :derps ).permit( 1 => [ :attribute, :another_attribute ], 2 => [ :attribute, :another_attribute ] )

permitted # To see what you'd get back in your controller

希望有了这个工具,您能够调试我的答案没有提供的任何东西,这比试错更容易。

68bkxrlz

68bkxrlz2#

最后一次编辑(希望):
我得从头开始重新考虑。我得出的结论是:既然: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

希望这对某人有帮助。

qq24tv8q

qq24tv8q3#

我见过的最好的解决方案是:

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]]})
e4yzc0pl

e4yzc0pl4#

这是我目前使用的方法。你可以像这样一个接一个地允许每个嵌套的参数:

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>}
6ss1mwsb

6ss1mwsb5#

这里是一种肮脏的方式来实现这一点的基础上的答案以上由格雷格布拉斯
这可以处理无限多个带有嵌套参数的索引

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

我相信有一个更好的方法来做到这一点,但这种方式是可读的,我可以很容易地告诉发生了什么事......最重要的是,它的工作

cigdeys3

cigdeys36#

在控制器中,到目前为止我发现的最干净的解决方案是这样的:

derp_params = params
  .permit(:derp => [:attribute, :another_attribute])
  .fetch(:derp) { {} }
  .values

如果您确实希望在缺少键时引发异常,请先调用#require或在#fetch中引发异常。

params.require(:derp)
derp_params = params
  .permit(:derp => [:attribute, :another_attribute])
  .fetch(:derp) { {} }
  .values

# or
derp_params = params
  .permit(:derp => [:attribute, :another_attribute])
  .fetch(:derp) { |key| raise ActionController::ParameterMissing, key, params.keys }
  .values

当然,如果您经常使用这种模式,您可以在ApplicationController中用一个方便的方法来 Package 所有这些。
额外提示:fields_for表单助手接受:index选项。

<% derps.each_with_index do |derp, index| %>
  <%= fields_for 'derps', derp, index: index do |f| %>
    <%= f.text_field :attribute %>
  <% end %>
<% end %>

# Will produce:
# <input name="derps[0][attribute]" ...etc.

相关问题