How can I iterate over part of a hash in Ruby - ruby-on-rails

In a Rails environment i get a params hash from a form.
Besides others, like
params[:vocab][:name]
params[:vocab][:priority]
I have the 3 fields tag_1, tag_2, tag_3 whose values are stored in
params[:vocab][:tag_1]
params[:vocab][:tag_2]
params[:vocab][:tag_3]
My question is:
Can I iterate over these three hash keys?
I want to do sth like
for i in 1..3 do
iterator = ":tag_" + i.to_s
puts params[:vocab][iterator.to_sym]
end
but that doesn't work.

Your approach doesn't work because:
':tag_2'.to_sym
# => :":tag_2"
so it would work if you remove leading colon from ":tag_" + i.to_s
You can also do it this way, iterating over keys:
[:tag_1, :tag_2, :tag_3].each { |key| puts params[:vocab][key] }

You can construct symbols via interpolation; prefixing a string with a colon will cause Ruby to interpret it as a symbol.
(1..3).each do |i|
puts params[:vocab][:"tag_#{i}"]
end

Related

rails controller invoking params of nested attributes

Submitting the following parameters
Parameters: {[...] "physicalinventario"=>{[...] "physicalinventarioitems_attributes"=>{"0"=>{"quantity"=>",85"}}}, "commit"
The goal is to intercept the quantity parameter at the physicalinventarioitem controller create action, and sanitize it for possible comma as decimal value being input
if params[:physicalinventario][:physicalinventarioitems_attributes][:quantity].include? ","
params[:physicalinventarioitem][:quantity] = params[:physicalinventario][:physicalinventarioitems_attributes][:quantity].tr!(',', '.').to_d
end
However, the syntax is wrong as no value after the comma is being handled.
#Alex answer is fine if you have only one quantity.
but what if you have multiple quantites,
eg: {"0"=>{"quantity"=>",85"},"1"=>{"quantity"=>",90"}}
So, here is the answer which also achieves that requirement for multiple nested attributes.
hash = {"physicalinventario"=>{"physicalinventarioitems_attributes"=>{"0"=>{"quantity"=>",85"},"1"=>{"quantity"=>",90"}}}}
The code that you require,
hash["physicalinventario"]["physicalinventarioitems_attributes"].each do |key, value|
if value["quantity"].include? ","
value["quantity"] = value["quantity"].tr!(',', '.').to_f
end
end
Here is the resultant hash,
`{"physicalinventario"=>{"physicalinventarioitems_attributes"=>{"0"=>{"quantity"=>0.85}, "1"=>{"quantity"=>0.9}}}}`
Looks like you've missed ["0"] in the chain to get :quantity.
Should be
params[:physicalinventario][:physicalinventarioitems_attribu‌tes]["0"][:quantity]
Most convenient Rails way to sanitize(normalize) data in a model.
To don't create duplicates, more here How best to sanitize fields in ruby on rails

Dynamically creating hash key name in Rails 4

Is it possible to dynamically create key names of a hash? I'm passing the following hash parameters:
params[:store][:store_mon_open(5i)]
params[:store][:store_mon_closed(5i)]
params[:store][:store_tue_open(5i)]
params[:store][:store_tue_closed(5i)]
.
.
.
params[:store][:store_sun_open(5i)]
params[:store][:store_sun_closed(5i)]
To check if each parameter exists, I'm using two arrays:
days_of_week = [:mon, :tue, ..., :sun]
open_or_closed = [:open, :closed]
But, I can't seem to figure out how to dynamically create the params hash (the second key( with the array. Here's what I have so far:
days_of_week.each do |day_of_week|
open_or_closed.each do |store_status|
if !eval("params[:store][:store_#{day_of_week}_#{store_status}(5i)").nil
[DO SOMETHING]
end
end
end
I've tried a bunch of things including the eval method (as listed above) but rails seems to dislike the parentheses around the "5i". Any help is greatly appreciated!
You should be able to do
if params[:store]["store_#{day_of_week}_#{store_status}(5i)".to_sym]
Note that you were missing the ? on .nil? and that !object.nil? can be shortened to just object
Assuming this is a HashWithIndifferentAccess, you should be able to access it via string just as you could with a symbol. Thus:
days_of_week.each do |day_of_week|
open_or_closed.each do |store_status|
key = "store_#{day_of_week}_#{store_status}(5i)"
unless params[:store][key]
# DO SOMETHING
end
end
end
If it's not a HashWithIndifferentAccess then you should just be able to call key.to_sym to turn it into a symbol.

How can I get the column name and value for an ActiveRecord association?

I want to get the column name and value. Here is the code I am working with:
#products.features.each do |feature|
puts feature.color
puts feature.size
puts feature.flavor
# etc....
end
I want to loop thru ... something like:
#products.features.each do |column, value|
puts column + ":" + value
end
I know I can create a Hash and map them in the controller. But I was wondering if there is a nicer way to do this.
#column_names is a method that gets all of an AR's column names in string form.
.collect(&:to_sym) calls to_sym on each one of these and puts them in an array.
column_names = Feature.column_names.collect(&:to_sym)
#products.features.each do |feature|
#iterate thru column names. btw string interpolation is better than using +
column_names.each { |column| puts "#{column} : #{feature.send(column)}" }
end

Rails syntax error assigning a variable with each loop

I'm trying to create a list of recipients to send in an external request by assigning it to a variable by doing the following:
recipients = #items.each do |item|
{"email"=>"#{Recipient.find_by_id(item.recip_id).email}", "amount"=>"#{item.price}"},
end
but I'm getting this error:
syntax error, unexpected ',', expecting '}'
I know that what I've done is not the right syntax. I'm kind of a Ruby newbie, so can someone help me figure out the correct syntax here?
EDIT: Thanks for the input. But what if I need to do two hashes for each item?
recipients = #items.map do |item|
{"email"=>"#{Recipient.find_by_id(item.recip_id).email}", "amount"=>"#{item.price}"},
{"email"=>"#{Store.find_by_id(item.recip_id).email}", "amount"=>"#{item.price}"}
end
The problem is with the comma at the end of the hash. Also if you want to store the email and amount in recipients, you should use map. This will return an array of hash with email and amount:
recipients = #items.map do |item|
{"email"=> Recipient.find_by_id(item.recip_id).email, "amount"=> item.price}
end
Also, as you might note, I don't need to pass the values of email and prices as a string.
If you want to return multiple hashes from your map block then you'd be better off switching to each_with_object:
Iterates the given block for each element with an arbitrary object given, and returns the initially given object.
So something like this:
recipients = #items.each_with_object([]) do |item, a|
a << {"email"=>"#{Recipient.find_by_id(item.recip_id).email}", "amount"=>"#{item.price}"}
a << {"email"=>"#{Store.find_by_id(item.recip_id).email}", "amount"=>"#{item.price}"}
end

Searching in a subhash with Ruby on Rails

I have a hash of hashes like so:
Parameters: {"order"=>{"items_attributes"=>{"0"=>{"product_name"=>"FOOBAR"}}}}
Given that the depth and names of the keys may change, I need to be able to extract the value of 'product_name' (in this example "FOOBAR") with some sort of search or select method, but I cannot seem to figure it out.
An added complication is that Params is (I think) a HashWithIndifferentAccess
Thanks for your help.
Is this what you mean?
if params.has_key?("order") and params["order"].has_key?("items_attributes") then
o = params["order"]["items_attributes"]
o.each do |k, v|
# k is the key of this inner hash, ie "0" in your example
if v.has_key?("product_name") then
# Obviously you'll want to stuff this in an array or something, not print it
print v["product_name"]
end
end
end

Resources