【问题标题】:Rails 4 Strong Params with multiple objects and integer keysRails 4 具有多个对象和整数键的强参数
【发布时间】:2015-11-03 20:55:53
【问题描述】:

我一次提交一个包含 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,但我正在努力解决这个问题 - 我不断收到“Unpermitted parameters: 1, 2”

我假设我需要执行以下操作:

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

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

类似的东西,但我已经尝试了所有我能想到的方法,但没有运气。

这里有什么想法吗?

【问题讨论】:

  • 什么是 mashes_params 中的 mashes?应该是derps
  • 好的,谢谢!更正了那个错字。那是我真正的代码。我使用 derps 作为一个通用示例。

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


【解决方案1】:

我发现命令行对于在 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

希望使用此工具,您将能够调试我的答案没有提供的任何东西,而不是反复试验。

【讨论】:

  • 关于控制台的好消息!谢谢。
【解决方案2】:

最终编辑(希望如此):

必须从头开始重新考虑这一点。我得出结论:既然 :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

呸。希望这对某人有所帮助。

【讨论】:

  • 这只有在你能保证你有不超过4个嵌套记录的情况下才有效,对吧?所以它似乎不是解决潜在问题的通用解决方案。
【解决方案3】:

我见过的绝对最好的解决方案是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]]})

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      这是一种基于 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
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多