I got this very confusing array of hashes as an API response.
http://jsfiddle.net/PP9N5/
( the full response is massive. Posting only a part of it but it covers all elements of the response)
How can I get to "airlines".
I tried this
<% #flight["air_search_result"]["onward_solutions"]["solution"].each do|h| %>
<strong><%=h["pricing_summary"]["total_fare"] %></strong> -
<% h["flights"]["flight"]["segments"]["segment"].each do |s| %>
<%= s['airline'] %>
<% end %> <br> <hr>
<% end %>
And I get this error
can't convert String into Integer
I did some modifications like
<%= h["flights"]["flight"]["segments"]["segment"].first["airline"] %>
Error received - can't convert String into Integer
and
<%= h["flights"]["flight"]["segments"]["segment"][0]["airline"] %>
Error received - undefined method '[]' for nil:NilClass
Isnt there a simple way, like I say to find a key "airline" and for that key it returns its value. I stumbled upon this link, though I dont get any error, I also dont get any result.
Thanks.
UPDATE
I did this
<% h["flights"]["flight"]["segments"]["segment"].each do |o,p| %>
<% if o=="airline" %> <%= p %> <% end %>
<% end %> <br> <hr>
<% end %>
I can get few values of airlines where inside segment there is no array.
For eg, i can get where departure_date_time is 2014-07-07T07:10:00, index = 5.
http://jsfiddle.net/PP9N5/1/ (scroll down)
Here is some code you can add which will extract all keys equal the parameter in any Hash within your Hash:
class Hash
def deep_find(query, &block)
flat_map do |key, value|
if key == query
yield value if block_given?
[value]
elsif value.is_a? Hash
value.deep_find(query, &block)
elsif value.is_a? Array
value.select { |i| i.is_a? Hash }.flat_map { |h| h.deep_find(query, &block) }
end
end
end
end
Example:
hash = {"h" => [{ 'x' => [1, 5] }, { 'x' => 2 }, { 'f' => { 'x' => [3, 4] } }], 'x' => 6 }
hash.deep_find('x') { |x| puts "#{x}" }
# [1, 5]
# 2
# [3, 4]
# 6
# => [[1, 5], 2, [3, 4], 6]
it's a tipical problem :D
Replace "=>" for ":" and render.
your_json = {.....}
your_json.gsub("=>", ":")
puts your_json
You can validate a JSON before to work it with http://jsonlint.com/.
Related
I'm trying to subtract the current item in the loop with the next indexed item, but I'm just getting the following error: undefined method `[]' for 0.0:Float
<% #trial.methods.each_with_index do |e, index| %>
<%= (e.total - e.total[index+1]) %><br />
<%= Time.at(e.try(:assessment).try(:assessment_date)/1000).strftime("%d/%m/%Y") %><br />
<%= e.try(:assessment).try(:degrees) %>
<% end %>
I think there is an easier way of doing that. Look at the following example.
# An array of 5 random numbers
a = [7,12,1,2,3]
# Iterate through the indices of the array
a.each_index do |i|
# We only show the result of a[i+1] - a[i]
# given i+1 is still in range of the array
puts "#{a[i+1] - a[i]}" if (i+1) < a.length
end
This should output 5 -11 1 1 each on a new line.
Similarly, you could do something like this:
<% #trial.methods.each_index do |i| %>
<% if i + 1 < e.total.length %>
<%= (e.total[i] - e.total[index+1]) %>
<% else %>
<%= 0 %>
<% end %>
<% end %>
Use #each_cons to build a subarray of consecutive pairs, then map it:
array = [7,12,1,2,3]
array.each_cons(2).map{ |e| e.last - e.first }
# => [5, -11, 1, 1]
A slight alternative:
array.each_cons(2).map{ |a, b| b - a }
Of course, you can change to a - b or whatever you need.
The first part does this:
array.each_cons(2).each {|e| p e}
# => [7, 12]
# => [12, 1]
# => [1, 2]
# => [2, 3]
You can use Enumerable#reduce to achieve this:
a = [7,12,1,2,3]
a.reduce(&:-) # -11
So for your case:
#trial.methods.map{|e| e.total}.reduce(&:-)
See https://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-reduce on its usage
I'm trying to permit an array with an arbitrary number of values, but Rails throws Unpermitted parameter: service_rates every time. I tried a lot of things (Rails 4 Unpermitted Parameters for Array, Unpermitted parameters for Dynamic Forms in Rails 4, ...) but nothing works.
The field's name is service_rates and it's column type is jsonb.
I want to create a JSON object from an arbitrary number of input fields:
<%= f.hidden_field :service_ids, value: #services.map(&:id) %>
<% #services.each do |service| %>
<tr>
<td>
<% value = #project.service_rates ? #project.service_rates["#{service.id}"]['value'] : '' %>
<%= text_field_tag "project[service_rates][#{service.id}]", value, class: 'uk-width-1-1', placeholder: 'Stundensatz' %>
</td>
</tr>
<% end %>
So my POST data looks like this:
project[service_rates][1] = 100
project[service_rates][2] = 95
project[service_rates][3] = 75
Currently service_rates is permitted via whitelisting with tap:
def project_params
params.require(:project).permit(:field1, :field2, […], :service_ids).tap do |whitelisted|
whitelisted[:service_rates] = params[:project][:service_rates]
end
end
At least, I'm building a JSON object in a private model function (which throws this error):
class Project < ActiveRecord::Base
before_save :assign_accounting_content
attr_accessor :service_ids
private
def assign_accounting_content
if self.rate_type == 'per_service'
service_rates = {}
self.service_ids.split(' ').each do |id|
service_rates["#{id}"] = {
'value': self.service_rates["#{id}"]
}
end
self.service_rates = service_rates
end
end
end
I've also tried to permit the field like that …
params.require(:project).permit(:field1, :field2, […], :service_rates => [])
… and that …
params.require(:project).permit(:field1, :field2, […], { :service_rates => [] })
… but this doesn't work either.
When I try this …
params.require(:project).permit(:field1, :field2, […], { :service_rates => [:id] })
… I get this: Unpermitted parameters: 1, 3, 2
It's not really clear what service_rates is for you. Is it the name of an association ? Or just an array of strings ?
To allow array of strings : :array => [],
To allow nested params for association : association_attributes: [:id, :_destroy, ...]
params.require(:object).permit(
:something,
:something_else,
....
# For an array (of strings) : like this (AFTER every other "normal" fields)
:service_rates => [],
# For nested params : After standard fields + array fields
service_rates_attributes: [
:id,
...
]
)
As I explained in the comments, the order matters. Your whitelisted array must appear AFTER every classic fields
EDIT
Your form should use f.fields_for for nested attributes
<%= form_for #project do |f| %>
<%= f.fields_for :service_rates do |sr| %>
<tr>
<td>
<%= sr.text_field(:value, class: 'uk-width-1-1', placeholder: 'Stundensatz' %>
</td>
</tr>
<% end %>
<% end %>
when i look at my console after submitting a form i can see like
Parameters: {"authenticity_token"=>"l0dqmb95MydzCWMugWdYt/2bGYyRyDF5ZfOGjrKhjfc=", "project_id"=>"second", "esthour"=>{"nonmodulhours_attributes"=>{"0"=>{"nonmodul_id"=>"61", "nonmodul_est_hours"=>"1"}, "1"=>{"nonmodul_id"=>"62", "nonmodul_est_hours"=>"9"}, "2"=>{"nonmodul_id"=>"63", "nonmodul_est_hours"=>""}}, "modul1hours_attributes"=>{"0"=>{"modul1_est_hours"=>"8", "modul1_id"=>"25"}, "1"=>{"modul1_est_hours"=>"", "modul1_id"=>"26"}**, "2"=>{"modul1_est_hours"=>"88", "modul1_id"=>"27"}}**, "ecommerce_est_hours"=>"", "modulhours_attributes"=>{"0"=>{"modul_est_hours"=>"8", "modul_id"=>"53"}, "1"=>{"modul_est_hours"=>"1", "modul_id"=>"54"}, "2"=>{"modul_est_hours"=>"8", "modul_id"=>"55"}}, "cms_est_hours"=>"", "nonmodul1hours_attributes"=>{"0"=>{"nonmodul1_id"=>"25", "nonmodul1_est_hours"=>"2"}, "1"=>{"nonmodul1_id"=>"26", "nonmodul1_est_hours"=>""}, "2"=>{"nonmodul1_id"=>"27", "nonmodul1_est_hours"=>"5"}}, "rfp_id"=>"35"}, "commit"=>"Add Todo", "utf8"=>"✓"}
here how can i arrange the attributes like line
"2"=>{"modul1_est_hours"=>"88", "modul1_id"=>"27"}}
to
"2"=>{ "modul1_id"=>"27","modul1_est_hours"=>"88",}}
**mean modul1_id before modul1_est_hours
form.html.erb**
<% #m1.map(&:id).each do |id|%>
<%= modul1(id) %> <%= f.hidden_field :modul1_id, :value => id %>
<%= f.number_field :modul1_est_hours, :size => 30 %>
</tr>
<% end %>
Edit
def get_issue_attribute_param1(u)
u.each do |key, value|
value.is_a?(Hash) ? get_issue_attribute_param1(value) : update_issue(key,value)
end
end
def update_issue(q,p)
if q.include?("_")
q1 = q.split("_")
q0 = q1[0]
if q1[0].include?("modul") && q1[1] == "id"
$id_map = p
puts $id_map
end
end
end
Here you go(in irb):
a = {"modul1_est_hours"=>"88", "modul1_id"=>"27"}
=> {"modul1_est_hours"=>"88", "modul1_id"=>"27"}
Hash[a.sort{|x,y| y.first <=> x.first }]
=> {"modul1_id"=>"27", "modul1_est_hours"=>"88"}
But, as everybody pointed out. If you could tell what you're trying to do, or what do you want with this? Then maybe what you're looking for maybe little more easy to understand and answer. :)
Edit
Here are the updated methods:
def get_issue_attribute_param1(params)
ids = []
params["esthour"].select{|hour| hour.include?('modul') }.each_pair do |key, value|
ids << update_issue(value)
end unless params["esthour"].nil?
ids # will have array of array like this: [["61", "62", "63"], ["25", "26", "27"], ["53", "54", "55"], ["25", "26", "27"]] for which you can do: `.flatten`
end
def update_issue(id_with_hours)
id_with_hours.values.map{|m| m.select{|v| v.include?('id') } }.map(&:values).flatten
end
Though I am not clear for what purpose you're using $id_map and hence I had to leave that scenario for you to handle. :)
I hope it helps.
I have an array [["Company Name", "Field6"], ["Email", "Field5"]]
And from that array I am creating array of fields with values:
[
[{:label=>"Company Name", :value=>"gfdgfd"}],
[{:label=>"Email", :value=>"gfdgfd#gfd.pl"}]
]
using
fields = [["Company Name", "Field6"], ["Email", "Field5"]]
# first element in array is Label and second is param id
fields_with_values = fields.collect do |field|
[
label: field[0],
value: params[field[1]]
]
end
and then I want to pass that labels and values to erb template(something like):
# template.erb
<% fields_with_values.each do |field| %>
l: <%= field.label %>
v: <%= field.value %>
<% end %>
How will be the best way to collect these fields_with_values ? Maybe I should use Object.new
Convert to a hash instead.
fields = [["Company Name", "Field6"], ["Email", "Field5"]]
fields_with_values = Hash[*fields.flatten]
# => {"Company Name"=>"Field6", "Email"=>"Field5"}
In your view, parse the hash:
<% fields_with_values.each do |label, value| %>
l: <%= label %>
v: <%= params[value.intern] %>
<% end %>
Note that this will break if your input array is uneven, ie. a key without a value.
EDIT
As mentioned in a comment below (+1), duplicate keys will not work. Fields that have the same label as another field are no good.
fields = [["Company Name", "Field6"], ["Email", "Field5"]]
# first element in array is Label and second is param id
fields_with_values = fields.collect do |label, param_id|
# It looks like there is no need for a nested array here, so just return a Hash
{
label: label,
value: params[param_id]
}
end
#=> [{:label=>"Company Name", :value=>"gfdgfd"}, {:label=>"Email", :value=>"gfdgfd#gfd.pl"}]
It looks like you are trying to use dot syntax to get values out of a Ruby Hash similar to how you would use dot syntax for a JavaScript object (e.g. field.label). Unfortunately this doesn't work for Ruby. I wish it did because it looks very clean. For the Ruby Hash you must use an index, which is a symbol in this case: field[:label]. Your ERB code will look something like this:
# template.erb
<% fields_with_values.each do |field| %>
l: <%= field[:label] %>
v: <%= field[:value] %>
<% end %>
The easy most basic way would be:
class Foo
attr_accessors :label, :value
def initialize (label, value)
#label = label
#value = value
end
end
fields_with_values = fields.map do |field|
Foo.new(field[0], params[field[1]])
end
from here on you can make it more Ruby way with splat operator or create the objects on the fly, etc. etc.
l:
v:
I would do
fields_with_values = fields.collect do |field|
{label: field[0], value: params[field[1]}
end
And in the view
<% fields_with_values.each do |field| %>
l: <%= field[:label] %>
v: <%= field[:value] %>
<% end %>
However, lets say label is a company and value is an e-mail. If you have a class like
class Company < SomethingOrNothing
attr_accessible :name, email
# methods here
end
You could do
#companies = fields.collect do |field|
Company.new(name: field[0], email: field[1])
end
And then
<% #companies.each do |company| %>
l: <%= comapny.name %>
v: <%= company.email %>
<% end %>
However, most likely creating a new class just for that is over engineering, unless you will use this class over and over in your code.
in an attempt to create a model with an array as an atribute, i ended up creating an array of hashes like so:
data1 = {}
data1[:name] = "Virtual Memory"
data1[:data] = #jobs.total_virtual_memory
data2 = {}
data2[:name] = "Memory"
data2[:data] = #jobs.total_memory
#data = []
#data << data1
#data << data2
which populates #data like this:
[{:data=>[#<Job day: "2010-08-02">, #<Job day: "2010-08-04">], :name=>"Virtual Memory"}, {:data=>[#<Job day: "2010-08-02">, #<Job day: "2010-08-04">], :name=>"Memory"}]
However i do not know how to acces these variables in the view. So as tu run somethig like:
for series in #data
series:name
for d in series:data
data:[Date, Value]
end
end
which would return something along the lines of:
Name1
Date1, Value1
Date2, Value 2,
Date3, Value 3,
Date4, Value 4,
Name2
Date1, Value 1,
Date2, Value 2,
Date3, Value 3,
Date4, Value 4,
This should work:
<% for series in #data %>
<%= series[:name] %>
<% for d in series[:data] %>
<%= d.date %>, <%= d.value %>
<% end %>
<% end %>
However you might consider using a more suitable datastructure instead of hashs. A Struct for example. This could look like this:
# in lib/JobData.rb:
JobData = Struct.new(:name, :data)
# in the controller:
data1 = JobData.new("Virtual Memory", #jobs.total_virtual_memory)
data2 = JobData.new("Memory", #jobs.total_memory)
#data = [data1, data2]
# in the view:
<% for series in #data %>
<%= series.name %>
<% for d in series.data %>
<%= d.date %>, <%= d.value %>
<% end %>
<% end %>
As a style point: I used for because you used for, but in general it's considered more rubyish to use each instead.
Here is the view:
<% for d in #data %>
{ pointInterval: <%= 1.day * 1000 %>,
name:<%= "'#{d[:name]}'"%>,
pointStart: <%= 2.weeks.ago.at_midnight.to_i * 1000 %>,
data: [
<% for chart in d[:data] %>
<%= "'[#{chart.day.to_time(:utc).to_i * 1000}, #{chart.data_attribute}],'" %>
<% end %>
]
},
<% end %>
Use #{d[:name]} to access the value of the "name" key and use d[:data] to access the array, then just loop throughthe array as if it were any normal array