Wes
Wes

Reputation: 764

Rails - Iterate Through Params

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

Answers (2)

James Milani
James Milani

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

Max Williams
Max Williams

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

Related Questions