Reputation: 764
I have a params which I pass that looks like this:
{"utf8"=>"✓",
"authenticity_token"=>"xx==",
"item_0"=>{"0"=>["address_1"], "1"=>["model 1"], "2"=>["ABC"], "3"=>["Off"], "4"=>["Status"]},
"item_1"=>{"0"=>["address_2"], "1"=>["model 1"], "2"=>["DEF"], "3"=>["On"], "4"=>["Status"]},
"item_2"=>{"0"=>["address_3"], "1"=>["model 1"], "2"=>["GHI"], "3"=>["On"], "4"=>["Status"]}}
How do I iterate over this param to get the values of each item? I know I can grab each item individually, but when submitting dynamic form data, I won't know the exact number of items that are in the params. How can I get around that problem?
Upvotes: 0
Views: 3115
Reputation: 1943
To keep only keys that you want, you could use Hash#keep_if
to do something like this:
hsh = {"utf8"=>"✓",
"authenticity_token"=>"xx==",
"item_0"=>{"0"=>["address_1"], "1"=>["model 1"], "2"=>["ABC"], "3"=>["Off"], "4"=>["Status"]},
"item_1"=>{"0"=>["address_2"], "1"=>["model 1"], "2"=>["DEF"], "3"=>["On"], "4"=>["Status"]},
"item_2"=>{"0"=>["address_3"], "1"=>["model 1"], "2"=>["GHI"], "3"=>["On"], "4"=>["Status"]}}
hsh.keep_if {|k, v| k=~ /item_/ }
and that would return:
{"item_0"=>{"0"=>["address_1"], "1"=>["model 1"], "2"=>["ABC"], "3"=>["Off"], "4"=>["Status"]},
"item_1"=>{"0"=>["address_2"], "1"=>["model 1"], "2"=>["DEF"], "3"=>["On"], "4"=>["Status"]},
"item_2"=>{"0"=>["address_3"], "1"=>["model 1"], "2"=>["GHI"], "3"=>["On"], "4"=>["Status"]}}
You can loop through a Hash
with each_pair
. Each pair takes to arguments e.g. |k, v|
representing the key/value pair. From there you can do as you'd like with the hash. Since your hash is nested, I drew up this example:
hsh = {"item_0"=>{"0"=>["address_1"], "1"=>["model 1"], "2"=>["ABC"],"3"=>["Off"], "4"=>["Status"]},
"item_1"=>{"0"=>["address_2"], "1"=>["model 1"], "2"=>["DEF"], "3"=>["On"], "4"=>["Status"]},
"item_2"=>{"0"=>["address_3"], "1"=>["model 1"], "2"=>["GHI"], "3"=>["On"], "4"=>["Status"]}}
> hsh.each_pair {|k, v| v.each_pair {|j, w| puts w } }
address_1
model 1
ABC
Off
Status
address_2
model 1
DEF
On
Status
address_3
model 1
GHI
On
Status
Here's a link to the docs for Hash#each_pair
.
There's a number of methods to loop through hashes. For example, each_key
and each_value
, which work pretty much as named.
Upvotes: 3
Reputation: 32933
hash = {"item_0"=>{"0"=>["address_1"], "1"=>["model 1"], "2"=>["ABC"], "3"=>["Off"], "4"=>["Status"]}, "item_1"=>{"0"=>["address_2"], "1"=>["model 1"], "2"=>["DEF"], "3"=>["On"], "4"=>["Status"]}, "item_2"=>{"0"=>["address_3"], "1"=>["model 1"], "2"=>["GHI"], "3"=>["On"], "4"=>["Status"]}}
hash.each do |k1, h1|
#eg: k1 = "item_0"; h1 = {"0"=>["address_1"], "1"=>["model 1"], "2"=>["ABC"], "3"=>["Off"], "4"=>["Status"]}
h1.each do |k2,arr|
#eg: k2 = "0"; arr = ["address_1"]
val = arr.first
puts "do something with k1 = #{k1.inspect}, k2 = #{k2.inspect}, val = #{val.inspect} here"
end
end
I use a similar sort of pattern with a request to update multiple objects, where I send through params with this structure:
params = {:resources => {123 => {:name => "Foo", :address => "bar"}, 456 => {:name => "Boo", :address => "Far"}}}
then in my code I can do
params[:resources].each do |id, attrs|
if resource = Resource.find_by_id(id)
resource.update_attributes(attrs)
end
end
which could be written in a more long-winded way as
params[:resources].each do |id, attrs|
if resource = Resource.find_by_id(id)
attrs.each do |k,v|
resource.send("#{k}=", v)
end
resource.save
end
end
Upvotes: 4