Reputation: 2168
I'm in a Rails controller. I try to take some params
and change some of the datas to update a model, but I also want to keep the original params
untouched.
The logical way to go is to use clone
or dup
but whatever I try, it fails and changes the original hash.
# 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
The result of product_params_without_suboptions
is correct. It set all the option_attribute
to nil
but when I try to call params
or product_params
it also changed there. Why isn't dup working here ?
Upvotes: 3
Views: 1585
Reputation: 5330
For me applying only .to_h
also was causing the original parameters to change.
The solution that worked for me was:
params.to_a.to_h.deep_clone
Upvotes: 0
Reputation: 2168
After some investigation, I realized params and its relatives are a ActionController::Parameters
class and not a simple hash output, which's logical to manipulate it with require
, except
, etc. I first thought it would fully act like a hash but it's not the case.
Doing a clone
, dup
, deep_dup
on it will just copy the class and because of the magic of rails, changing anything in this copy will lead to a global change. I don't know the exact reason of this behaviour but I guess there's some class variables / singleton pattern going on.
The simplest solution I found was to convert it to a hash via to_h
so it cut out this problem. You can do params_hash = params.to_h
and then manipulate the hash and it won't have any consequence on the original params
object.
Upvotes: 7
Reputation: 54223
If you have a nested hash and want to duplicate everything, you might be interested by deep_dup
Your product_params is an Array of Hashes of Hash, right? Your example had strings as keys, but your code had symbols. Adapt accordingly.
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"}}}]
Upvotes: 3