Searching in a subhash with Ruby on Rails - 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

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

Split parameters into component parts

I have the following parameters when I process a form with multiple records. I wish to be able to take each individual campaign and process it accordingly.
Parameters: {"utf8"=>"✓", "authenticity_token"=>"F2Mciu313dYUBOh7Ju0gSXrKa/yz6D6qZlVBMKOch4k=", "campaign"=>{"2"=>{"start_date"=>"2016-07-18 15:43:00", "end_date"=>"2016-10-15 12:20:00", "merchant_revenue"=>"10", "status"=>"Rejected", "notes"=>"aaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "1"=>{"start_date"=>"2016-07-15 12:20:00", "end_date"=>"", "merchant_revenue"=>"10", "status"=>"Rejected", "notes"=>"bbbbbbbbbbbbbbbbbbbbbbbbbb"}}, "Commit"=>"Process"}
How do I split this data so each record has a campaign contained within. Thanks.
you have campaign as hash just loop over it and process hash value
params["campaign"].each do |_key, value|
# process(value)
end
If you want to loop over all the campaign objects individually then you can try this:
params["campaign"].each do |k,v|
puts v
end
v will contain the params of each campaign. Hope it helps you get in the right direction.
As stated by others, all you need to do is loop over the campaign object to access each item. Once you gain access to it, you can process it like this:
params[:campaign].each do |key,value|
value[:status] # gives you the value of status key in each campaign
end

How can I iterate over part of a hash in Ruby

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

Erase Blank Json Loop

I have a rails backend that recieves JSON that (when parsed) looks like:
[
{"kind"=>"Magazine", "price"=>["$20.99"]},
{"kind"=>"Book", "price"=>"", "title"=>""}
]
Basically what I want to do is for each kind of product (e.g. Magazine or book), if all other attributes except for the kind key are blank, then don't save that array key/value. So in my example, Magazine would stay in the array, but the Book kind would be deleted (because both attributes price and title are blank.
I know I could loop through with something like (list is the parsed JSON before):
list.each do |l|
if l["kind"] == "Magazine"
if l["price"].blank?
# THEN DELETE THIS ITERATION
end
end
end
but this seems very repetitive and not clean. How do I do this better?
The idiomatic way to do this would involve using Array#reject! to remove the unwanted lines. You can also extract just the values, remove the blank ones, and count the remaining values... making sure that 'kind' is one of them...
list.reject! {|item| item.values.reject(&:blank?).size < 2 && item['kind'].present?}
Notice the difference between reject and reject! ... one returns a new hash while the ! method modifies it in place.
You can extend Hash with a method to remove blank values (this supports nested hashes also):
class Hash
def delete_blank
delete_if{|k, v| v.blank? or v.instance_of?(Hash) && v.delete_blank.blank?}
end
end
And after the blank values are removed, if there is only one key left and it is kind, then remove the array element:
list.each do |l|
l.delete_blank
end
list.reject! {|l| l.key?('kind') && l.length < 2}
#=> [{"kind"=>"Magazine", "price"=>["$20.99"]}]

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.

Resources