在Rails参数中使用dup和clone的明显问题

时间:2016-11-09 15:12:36

标签: ruby-on-rails ruby

我在Rails控制器中。我尝试使用一些params并更改一些数据来更新模型,但我也想保持原始params不受影响。

合理的方法是使用clonedup,但无论我尝试什么,它都会失败并更改原始哈希值。

# Original product_params which is set as params.require(:product)
{"name"=>"Product 2",
 "brand"=>"Brand 2",
 "desc"=>"Placeat a sunt eos incidunt temporibus.\r\n\r\nReprehenderit repudiandae amet quibusdam dolorem et. Itaque commodi at.",
 "hs_code"=>"12212121",
 "options_attributes"=>
  {"0"=>{"name"=>"hkjlVariation 4", "suboptions_attributes"=>{"0"=>{"name"=>"Chkjlhoice 0", "id"=>"582209026b710eded24ecd12"}}, "id"=>"582209026b710eded24ecd13"},
   "1"=>
    {"name"=>"hhVhariation h5kkk",
     "suboptions_attributes"=>{"0"=>{"name"=>"Choice 0kh", "id"=>"582209026b710eded24ecd14"}, "1"=>{"name"=>"hkjChoice 1", "id"=>"582209026b710eded24ecd16"}, "2"=>{"name"=>"kkk"}},
     "id"=>"582209026b710eded24ecd15"},
   "2"=>{"name"=>"lh", "suboptions_attributes"=>{"0"=>{"name"=>"klhj"}}}}}

# Method to change the `suboptions_attributes` to `nil`
def product_params_without_suboptions
  copy = product_params.dup
  copy.tap do |product_param|
    product_param[:options_attributes].each do |key, option_attribute|
      unless option_attribute[:suboptions_attributes].nil?
        option_attribute[:suboptions_attributes] = nil
      end
    end
  end
end

# We define product_params
def product_params
  params.require(:product).permit!
end

product_params_without_suboptions的结果是正确的。它将所有option_attribute设置为nil,但当我尝试拨打paramsproduct_params时,它也会在那里发生变化。 为什么不在这里工作?

3 个答案:

答案 0 :(得分:2)

如果您有嵌套哈希并想要复制所有内容,那么您可能会感兴趣deep_dup

你的product_params是哈希哈希数组,对吧? 您的示例将字符串作为键,但您的代码具有符号。相应调整。

product_params = [{"name"=>"Product 2",
                   "brand"=>"Brand 2",
                   "desc"=>"Placeat a sunt eos incidunt temporibus.\r\n\r\nReprehenderit repudiandae amet quibusdam dolorem et. Itaque commodi at.",
                   "hs_code"=>"12212121",
                   "options_attributes"=>
{"0"=>{"name"=>"hkjlVariation 4", "suboptions_attributes"=>{"0"=>{"name"=>"Chkjlhoice 0", "id"=>"582209026b710eded24ecd12"}}, "id"=>"582209026b710eded24ecd13"},
 "1"=>
{"name"=>"hhVhariation h5kkk",
 "suboptions_attributes"=>{"0"=>{"name"=>"Choice 0kh", "id"=>"582209026b710eded24ecd14"}, "1"=>{"name"=>"hkjChoice 1", "id"=>"582209026b710eded24ecd16"}, "2"=>{"name"=>"kkk"}},
 "id"=>"582209026b710eded24ecd15"},
 "2"=>{"name"=>"lh", "suboptions_attributes"=>{"0"=>{"name"=>"klhj"}}}}}]

require 'pp'

copy = product_params.deep_dup
copy.each do |product_param|
  product_param["options_attributes"].each do |key,option_attribute|
    option_attribute.delete("suboptions_attributes")
  end
end

pp product_params
puts "--------"
pp copy

# [{"name"=>"Product 2",
#   "brand"=>"Brand 2",
#   "desc"=>
#    "Placeat a sunt eos incidunt temporibus.\r\n\r\nReprehenderit repudiandae amet quibusdam dolorem et. Itaque commodi at.",
#   "hs_code"=>"12212121",
#   "options_attributes"=>
#    {"0"=>
#      {"name"=>"hkjlVariation 4",
#       "suboptions_attributes"=>
#        {"0"=>{"name"=>"Chkjlhoice 0", "id"=>"582209026b710eded24ecd12"}},
#       "id"=>"582209026b710eded24ecd13"},
#     "1"=>
#      {"name"=>"hhVhariation h5kkk",
#       "suboptions_attributes"=>
#        {"0"=>{"name"=>"Choice 0kh", "id"=>"582209026b710eded24ecd14"},
#         "1"=>{"name"=>"hkjChoice 1", "id"=>"582209026b710eded24ecd16"},
#         "2"=>{"name"=>"kkk"}},
#       "id"=>"582209026b710eded24ecd15"},
#     "2"=>{"name"=>"lh", "suboptions_attributes"=>{"0"=>{"name"=>"klhj"}}}}}]
# --------
# [{"name"=>"Product 2",
#   "brand"=>"Brand 2",
#   "desc"=>
#    "Placeat a sunt eos incidunt temporibus.\r\n\r\nReprehenderit repudiandae amet quibusdam dolorem et. Itaque commodi at.",
#   "hs_code"=>"12212121",
#   "options_attributes"=>
#    {"0"=>{"name"=>"hkjlVariation 4", "id"=>"582209026b710eded24ecd13"},
#     "1"=>{"name"=>"hhVhariation h5kkk", "id"=>"582209026b710eded24ecd15"},
#     "2"=>{"name"=>"lh"}}}]

答案 1 :(得分:2)

工作解决方案

经过一番调查后,我意识到params及其亲属是ActionController::Parameters类而不是简单的哈希输出,用requireexcept来操纵它是合乎逻辑的,我首先认为它完全像哈希一样,但事实并非如此。

在其上执行clonedupdeep_dup只会复制该类,并且由于rails的魔力,更改此副本中的任何内容都将导致全局更改。我不知道这种行为的确切原因,但我猜有一些类变量/单例模式正在进行。

我找到的最简单的解决方案是通过to_h将其转换为哈希,以便解决这个问题。您可以执行params_hash = params.to_h然后操纵哈希,它不会对原始params对象产生任何后果。

答案 2 :(得分:0)

对我来说,仅应用.to_h也会导致原始参数发生变化。 对我有用的解决方案是:

params.to_a.to_h.deep_clone