I am trying to format date by iterating through the #data json formatted input shown as below.
#data= JSON.parse(request,symbolize_names: true)[:data]
#data = #data.each{ |key,val| k = Date.parse(key).strftime("%Y %m") }
But this way it is showing error "no implicit conversion of Symbol into String".
Could any one please help?
If you're iterating over a hash where the keys are symbols, then the error is telling you where and what's the problem. In order to parse a date, you must pass a string as argument, and as you haven't converted such object, then you're getting the error.
Try using to_s, to convert the symbol to string:
#data.each do |key, _|
puts Date.parse(key.to_s).strftime '%Y %m'
end
Note if you're inside a block, and you're not going to use the k variable you're creating, then you can avoid creating it, it won't be available outside the block. You're just printing the parsed date.
If you're not going to use the value block variable, then you can omit it.
As pointed #mu, you can omit the symbolize_names: true, and this way the keys will be strings, then, the conversion isn't needed:
require 'date'
require 'json'
request = '{
"data": {
"2017-11-22 00:22:26": "foo" ,
"2017-11-22 00:22:27": "bar"
}
}'
#data = JSON.parse(request)['data']
#data.each do |key, _|
puts Date.parse(key).strftime '%Y %m'
end
request is an approximation to your real data.
Related
I made a table component using react js, which uses columns to display data (which works fine with other data). For example, column 1 would show the title, column 2 the year, and column 3 the format.
Here is an example of my JSON:
{"movies": [{"title": "Iron Man", "year": "2008", "format": "DVD"}, {"title": "Iron Man 2", "year": "2010", "format": "DVD"}, {"title": "Iron Man 3", "year": "2013", "format": "DVD"}]}
Here is my code to populate the table, but it does not seem to work:
#movieList = #Makes a call to my mock API to get list of movies
#movies = Array.new
#movieList.each do |item|
#movie = Hash.new
#movie[:column1] = item[:title]
#movie[:column2] = item[:year]
#movie[:column3] = item[:format]
#movies << #movie
end
I need some advice to overcome a "no implicit conversion of symbol into integer error" I get. Could anyone offer some advice and point out where I am going wrong?
tl;dr
use #movieList["movies"].each
explanation
The issue here, is that you act as though your #movieList is ann array, when it is actually a hash (assuming #movieList is the JSON you showed).
each works on both arrays and hashes. However, when you use it on a hash, the block is passed |key, val|. Also, assigning block variables is optional. So, when you say #movieList.each do |item|, item is actually the top level key of the hash ("movies").
Strings such as "movies" respond to [] indexing with numbers. That's why you get the error no implicit conversion of symbol into integer ... because you pass a symbol to String#[] and it expects an integer.
Another way to write this code, that is more idiomatic, would be like so:
#movies = #movieList["movies"].map do |movie|
{
column1: movie["title"],
column2: movie["year"],
column3: movie["format"]
}
end
try reassigning
#movieList = #movieList[:movies] this will solve your problem. You're trying to iterate a object instead of an array.
lemme know if it solves your problem.
You need to loop movies using #movieList["movies"] as your JSON is a hash that has a key 'movies' and an array of movies as a value => {'movies': [{...},{...},...]}
As #max pleaner explained assigning block variables is optional, but when you use each on a hash(your JSON in this case) and provide only one block variable (instead of two refering to the keys and values of the hash), your key-value pairs are converted to two-element arrays inside the block where first element is the key and second one is the value of the pair.
Your item looks like this inside your each block -
['movies', [{movie1}, {movie2},..]], hence:
item[0] # 'movies'
item[1] # [{movie1}, {movie2},...]
As arrays expect indexing with integers and you supply symbol (item[:title]), you receive:
TypeError (no implicit conversion of Symbol into Integer)
I am Having an issue where if a name comes in with a ' or " my JSON parsing fails. I want to know how i can avoid this.
This is my current code:
def create
puts params
##contact = Contact.new(contact_params)
##contact.user = current_user
contactsParam = params[:contacts]
if contactsParam
# contactsParam.each do |contact|
# end
contactValues = contactsParam.map { |c|
puts "dulce!!! : " + c.to_s
json = JSON.parse(c)
result = "('#{json['name']}', '#{json['phone_number']}', '#{json['detail']}', '#{json['image_url']}', '#{json['email']}', '#{json['address']}', '#{json['city']}', '#{json['state']}', '#{json['zipcode']}', '#{json['country']}', #{current_user.id}, now(), now())"
result
}.join(",")
if contactValues.length > 0
ActiveRecord::Base.connection.execute("INSERT INTO contacts (name, phone_number, detail, image_url, email, address, city, state, zipcode, country, user_id, created_at, updated_at) VALUES #{contactValues}")
end
end
here is an example of a JSON String that fails (i added a bunch of random characters to test).
{"name":"Aaacontacttest'/'#"-jgg&$;$/&/#.'sheh","phone_number":",7*#;878545848487849648","detail":"","image_url":"","email":"test#test.com","address":"-/:;()$#""":$;$:$$/!:!/!,!6677bhgv
2017-07-25T20:08:54.614283+00:00 app[web.1]: Hsbsbsbb7788$!","city":"Hehshdbdb","state":"HSSHHSHS$&:$:$","zipcode":"3319)","country":"United States"}
1.
Let's first correct the JSON Object which you gave:
{
"name":"Aaacontacttest'/'#"-jgg&$;$/&/#.'sheh",
"phone_number":",7*#;878545848487849648",
"detail":"",
"image_url":"",
"email":"test#test.com",
"address":"-/:;()$#""":$;$:$$/!:!/!,!6677bhgv2017-07-25T20:08:54.614283+00:00 app[web.1]: Hsbsbsbb7788$!",
"city":"Hehshdbdb",
"state":"HSSHHSHS$&:$:$",
"zipcode":"3319)",
"country":"United States"
}
The problem with this JSON object is, it is not closed properly. If you wanted to use quotes in your object then please use Backslash to omit to close the value of the object.
Let's convert the above invalid JSON Object to valid JSON object first, such ruby avoid syntax error:
{
"name":"Aaacontacttest'/'#\"-jgg&$;$/&/#.'sheh",
"phone_number":",7*#;878545848487849648",
"detail":"",
"image_url":"",
"email":"test#test.com",
"address":"-/:;()$#\"\"\":$;$:$$/!:!/!,!6677bhgv2017-07-25T20:08:54.614283+00:00 app[web.1]: Hsbsbsbb7788$!",
"city":"Hehshdbdb",
"state":"HSSHHSHS$&:$:$",
"zipcode":"3319)",
"country":"United States"
}
What we did over here:
Initial Hash object with the "name" as the key has a value:
"name":"Aaacontacttest'/'#"-jgg&$;$/&/#.'sheh"
Area with bold depicting that you have closed the value with quotes where rest of the Italic character is marked as invalid.
Types of errors which ruby would be raised either "syntax error" or unexpected 'any char', expecting end-of-input
We have introduced backslash in the value to ensure proper closing of the value.
"name":"Aaacontacttest'/'#\"-jgg&$;$/&/#.'sheh"
So where ever you have used quotes in your value please omit them using backslash.
The object which you gave is the normal hash object not a JSON object in case of ruby, as Ruby JSON parser expects the argument to be a string and can’t convert objects like a hash or array.
If you do JSON.generate(hash) you will get the JSON object:
Note: hash if the corrected hashobject.
Adding JSON object over here.
"{\"name\":\"Aaacontacttest'/'#\\"-jgg&$;$/&/#.'sheh\",\"phone_number\":\",7*#;878545848487849648\",\"detail\":\"\",\"image_url\":\"\",\"email\":\"test#test.com\",\"address\":\"-/:;()$#\\"\\"\\":$;$:$$/!:!/!,!6677bhgv2017-07-25T20:08:54.614283+00:00 app[web.1]: Hsbsbsbb7788$!\",\"city\":\"Hehshdbdb\",\"state\":\"HSSHHSHS$&:$:$\",\"zipcode\":\"3319)\",\"country\":\"United States\"}"
If you do JSON.parse(HashObject not JSONobject) the ruby would throw an error:
TypeError: no implicit conversion of Hash into String
Summary:
Correct your hashObject.
Convert you hashObject into the valid JSON object for ruby. If you wanted to generate JSON use JSON.generate(hash) method.
I'm grabbing a JSON hash from my server and trying to read it in my ruby script. It seems to be returning the wrong value though, unless I'm just loosing my mind:
I'm calling this from a function:
def get_functions(serial_number)
response = HTTParty.get("#{get_host_url}/v1/devices/#{serial_number}.json")
data = response['scan_option']
return data
end
Here is the returned JSON:
{"can_scan"=>true, "can_brute_ssh"=>false, "can_brute_telnet"=>false, "can_brute_voip"=>false, "can_brute_smtp"=>false, "can_brute_pop3"=>false, "can_google_crawl"=>false, "can_scan_external_ip"=>false, "scan_ip_list"=>["10.10.10.1"], "exclude_ip_list"=>[]}
Which is then read into the following code:
data.each do |d|
#can_scan = d['can_scan']
# ....
end
However this is throwing an error:
no implicit conversion of String into Integer
{foo: :bar}.each do |d|
p d
d['meow']
end
# => [:foo, :bar]
#! TypeError: no implicit conversion of String into Integer
Hash#each yields a two element array ([key, value]). You then try to index that array with d["can_scan"], which fails as arrays can only be indexed with integers.
Instead, directly access the value - data['can_scan'].
I you mean that data in your third snippet (where you call data.each) is the hash mentioned just above it, indeed that would be troublesome. Calling each on a hash will itterate over its key, value pairs, giving you an array in the block var d of the data.each (with a [key, value] pair in it).
You might just want to call data['can_scan'].
Note that the return at the end of your method defenition is not needed in Ruby. You can just do:
def get_functions(serial_number)
response = HTTParty.get("#{get_host_url}/v1/devices/#{serial_number}.json")
response["scan_option"]
end
I'm using a module within my Rails App to perform some actions and render a html file and save it to S3. So far so good, apart from the fact that I need to pass a currency variable to to be rendered and erb is throwing this error:
undefined method `/' for "3,395,000":String
Here's my code:
options = {
...
price: Money.new(#case.cash_price / 100.to_i, "DKK").format.to_s.html_safe,
...
}
And here's my module:
def generate_html(options)
require 'erb'
erb_file = "templates/banners/widesky.html.erb"
erb_str = File.read(erb_file)
...
#price = options[:price]
...
renderer = ERB.new(erb_str)
result = renderer.result(binding)
FileUtils.mkdir_p('temp') unless File.directory?('temp')
File.open('temp/index.html', 'w') do |f|
f.write(result)
end
'temp/index.html'
end
And I tried formatting the currency in different ways, but I always get the same error. Any ideas why?
EDIT
#case.cash_price originally is an Integer. I want to convert it to a string with commas (hence using Money to format it). The problem seems to be that erb doesn't like the formatted result and throw the above error.
If for some reason you cannot use any gem/helper, let's reinvent the wheel!
def to_currency(price_in_cents, currency=nil, decimal_separator = '.', thousand_separator = ',')
price_in_cents.to_s.rjust(3,'0').reverse.insert(2,decimal_separator).gsub(/(\d{3})(?=\d)/, '\1'+thousand_separator).reverse+(currency ? " #{currency}" : '')
end
puts to_currency(123456789, 'DKK')
puts to_currency(123456, '€', ',', ' ')
puts to_currency(1)
It outputs :
1,234,567.89 DKK
1 234,56 €
0.01
Note that price_in_cents should be either a String that looks like an Integer ("123456789") or an Integer (123456789), but not a preformatted String ("123,456.78") or a Float (1.23).
Finally, the resulting String is as unsafe as price_in_cents :
to_currency("unsafe_codejs")
=> "unsafe_code.js"
You don't have to specify html_safe on the result anyway, because nothing would be escaped in "1,234,567.89 DKK".
Original answer :
If cash_price is a String with commas, you need to remove the commas first, then convert it to a float, then divide by 100, and then convert the result to an Integer.
cash_price.to_s is to avoid getting errors if cash_price does come as a Numeric.
price: Money.new((#case.cash_price.to_s.delete(',').to_f/100).to_i, "DKK").format.to_s.html_safe
#case.cash_price is a string so you can't perform any mathematical operations on it. You would need to convert the value to an integer (3395000) rather than a comma delimited string as you currently have ('3,395,000').
A side note, 100.to_i is redundant as 100 is already an integer, unless you wanted to convert the equation to an integer, which would need brackets (#case.cash_price / 100).to_i.
This seems ludicrously simple but I cannot figure out how to convert a hash-string to a hash.
When I do a Answer.find_by_sql I get a string like this
deepthought = "\"answertolife\"=>\"42\""
But I cannot figure out how to turn that into a hash.
I have tried:
pry(main)> Hash[deepthought]
ArgumentError: odd number of arguments for Hash
pry(main)> JSON.parse deepthought
JSON::ParserError: 757: unexpected token at '"answertolife"=>"42"'
pry(main)> deepthought.to_json
=> "\"\\\"answertolife\\\"=>\\\"42\\\"\""
I saw How do I convert a String object into a Hash object?, but I still cannot figure it out.
Try this
eval("{ #{deepthought} }")
It wraps the deepthought string with curly brace { }, and then use eval
A bit late but if you need to convert a multiple entries this works great.
def hstore_to_hash(hstore)
values = {}
hstore.gsub(/"/, '').split(",").each do |hstore_entry|
each_element = hstore_entry.split("=>")
values[each_element[0]] = each_element[1]
end
values
end
Rails4 supports hstore out of the box so I'd probably handle the string casting the same way Rails4 does it. If you look inside the Rails4 PostgreSQL-specific casting code, you'll find string_to_hstore:
def string_to_hstore(string)
if string.nil?
nil
elsif String === string
Hash[string.scan(HstorePair).map { |k, v|
v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
[k, v]
}]
else
string
end
end
and a little lower down in the same file, you'll find HstorePair:
HstorePair = begin
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
/(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
end
Stash that somewhere convenient (probably somewhere in lib/) and send your hstore strings through that string_to_hstore to unpack them into Hashes.
This seems to work but feels dirty.
JSON.parse "{ #{deepthought} }".gsub('=>', ':')