I'm trying to write app which logs json msgs to db. That part I got. The problem comes with getting that json back. I can't get values from it.
I've tried to get raw msgs from db and getting values from this ( json gem seems not to see it as json)
I've tried to parse it via .to_json , but it doesn't seem to work either. Maby you have some idea how to get it?
Thanks in advance
table:
mjl_pk bigserial
mjl_body text <- JSON is stored here
mjl_time timestamp
mjl_issuer varchar
mjl_status varchar
mjl_action varchar
mjl_object varchar
mjl_pat_id varchar
mjl_stu_id varchar
code:
#Include config catalog, where jsonadds is
$LOAD_PATH << 'config'
#Requirements
require 'sinatra'
require 'active_record'
require 'json'
require 'jsonadds'
require 'RestClient'
#Class for db
class Mjl < ActiveRecord::Base
#table name
self.table_name = "msg_json_log"
#serialization
serialize :properties, JSON
#overwrite ActiveRecord id with "mjl_pk"
def self.primary_key
"mjl_pk"
end
end
#Get json msg and write it to db
post '/logger' do
content_type :json
#Check if msg is json
if JSON.is_json?(params[:data])
#insert data into db
msg = Mjl.create(:mjl_body => params[:data] ,:mjl_issuer => 'LOGGER', :mjl_action => 'test', :mjl_object =>'obj')
else
#else return error
puts "Not a JSON \n" + params[:data]
end
end
#Get json with id = params[:id]
get '/json/:id' do
content_type :json
#Get json from db
json_body = Mjl.where(mjl_pk: params[:id]).pluck(:mjl_body)
puts json_body
json_body = json_body.to_json
puts json_body
#Get 'patientData' from json
puts json_body['key']
puts json_body[0]['key']
end
Output:
{
"key": "I am a value",
"group": {
"key2": "Next value",
"key3": "Another one"
},
"val1": "Val"
}
["{\n \"key\": \"I am a value\",\n \"group\": {\n \"key2\": \"Next value\",\n \"key3\": \"Another one\"\n },\n \"val1\": \"Val\"\n}"]
key
<--empty value from 'puts json_body[0]['key']'
I've also created a JSON Log in my project like this, this might help you...
In Controller
current_time = Time.now.strftime("%d-%m-%Y %H:%M")
#status_log = {}
#arr = {}
#arr[:status_id] = "2.1"
#arr[:status_short_desc] = "Order confirmed"
#arr[:status_long_desc] = "Order item has been packed and ready for shipment"
#arr[:time] = current_time
#status_log[2.1] = #arr
#status_log_json = JSON.generate(#status_log)
StoreStock.where(:id => params[:id]).update_all(:status_json => #status_log_json)
In View
#json_status = JSON.parse(ps.status_json) # ps.status_json contails raw JSON Log
= #json_status['2.1']['status_long_desc']
Hope this might help you.
when you are doing
json_body = Mjl.where(mjl_pk: params[:id]).pluck(:mjl_body)
you already have json
so no need doing
json_body = json_body.to_json
Since doing this you get the string representation of json, just remove that line and you will get all the values.
Finally I've found how to do it.
I saw explanation on JSON methods at:
from json to a ruby hash?
Code which works for me:
json_body = Mjl.where(mjl_pk: params[:id]).pluck(:mjl_body)
puts json_body
jparsed = JSON.parse(json_body[0])
puts jparsed['key']
Related
I tried something like this with vine gem but not working. Is there any other smart way
Note i do not want to use complex Hash Class like we have here
require 'vine'
require 'json'
json = '{
"name":"John",
"address":{
"street":"street 1",
"country":"country1"
},
"phone_numbers":[
{
"type":"mobile",
"number":"234234"
},
{
"type":"fixed",
"number":"2342323423"
}
]
}'
h = JSON.parse(json)
{"name"=>"John", "address"=>{"street"=>"street 1", "country"=>"country1"}, "phone_numbers"=>[{"type"=>"mobile", "number"=>"234234"}, {"type"=>"fixed", "number"=>"2342323423"}]}
a = h.access("phone_numbers.0.type")
mobile
b = h.set("phone_numbers.0.type", "tablet")
{"name"=>"John", "address"=>{"street"=>"street 1", "country"=>"country1"}, "phone_numbers"=>{0=>{:type=>"tablet"}}}
expected result is
{"name"=>"John", "address"=>{"street"=>"street 1", "country"=>"country1"}, "phone_numbers"=>[{"type"=>"tablet", "number"=>"234234"}, {"type"=>"fixed", "number"=>"2342323423"}]}
It is not working for array, or i am missing something
Thanks
Try the below:
require 'json'
#considering that the json is same as you mentioned in the question
h = JSON.parse(json)
# For accessing name
p h['name']
#for changing the name
h['name'] = 'ABC'
# for getting address
p h['address']['street']
# for setting address
h['address']['street'] = "my street"
#get phone number
h['phone_numbers'].each do |ph|
p ph['type']
#Set mobile number
ph['number'] = "123"
end
In the above you received a single object in json.
But in case if you receive multiple objects, then parse them like below
json_array = JSON.parse(json)
json_array.each do |h|
#All the above steps will remain same
end
My Rails app is reading in JSON from a Bing API, and creating a record for each result. However, when I try to save one of the nested JSON attributes, I'm getting Resource creation error: no implicit conversion of String into Integer.
The JSON looks like this:
{
"Demo": {
"_type": "News",
"readLink": "https://api.cognitive.microsoft.com/api/v7/news/search?q=european+football",
"totalEstimatedMatches": 2750000,
"value": [
{
"provider": [
{
"_type": "Organization",
"name": "Tuko on MSN.com"
}
],
"name": "Hope for football fans as top European club resume training despite coronavirus threat",
"url": "https://www.msn.com/en-xl/news/other/hope-for-football-fans-as-top-european-club-resume-training-despite-coronavirus-threat/ar-BB12eC6Q",
"description": "Bayern have returned to training days after leaving camp following the outbreak of coronavirus. The Bundesliga is among top European competitions suspended."
}
}
The attribute I'm having trouble with is [:provider][:name].
Here's my code:
def handle_bing
#terms = get_terms
#terms.each do |t|
news = get_news(t)
news['value'].each do |n|
create_resource(n)
end
end
end
def get_terms
term = ["European football"]
end
def get_news(term)
accessKey = "foobar"
uri = "https://api.cognitive.microsoft.com"
path = "/bing/v7.0/news/search"
uri = URI(uri + path + "?q=" + URI.escape(term))
request = Net::HTTP::Get.new(uri)
request['Ocp-Apim-Subscription-Key'] = accessKey
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
end
response.each_header do |key, value|
# header names are coerced to lowercase
if key.start_with?("bingapis-") or key.start_with?("x-msedge-") then
puts key + ": " + value
end
end
return JSON(response.body)
end
def create_resource(news)
Resource.create(
name: news['name'],
url: news['url'],
description: news['description'],
publisher: news['provider']['name']
)
end
I looked at these questions, but they didn't help me:
Extract specific field from JSON nested hashes
No implicit conversion of String into Integer (TypeError)?
Why do I get "no implicit conversion of String into Integer (TypeError)"?
UPDATE:
I also tried updating the code to:
publisher: news['provider'][0]['name'], but I received the same error.
because "provider" is an array.
it should be accessed with index.
[:value][0][:provider][0][:name]
same goes with "value".
I have a Ruby array of students. Student class has attributes id, name and age.
students = [
{id:"id1",name:"name1",age:"age1"},
{id:"id2",name:"name2",age:"age2"},
{id:"id3",name:"name3",age:"age3"}
]
I want to create a JSON key value object from this array as follows.
json_object = {id1:name1, id2:name2, id3:name3}
input = [ {id:"id1",name:"name1",age:"age1"},
{id:"id2",name:"name2",age:"age2"},
{id:"id3",name:"name3",age:"age3"}]
require 'json'
JSON.dump(input.map { |hash| [hash[:id], hash[:name]] }.to_h)
#⇒ '{"id1":"name1","id2":"name2","id3":"name3"}'
Give this a go:
students = [
{id:"id1",name:"name1",age:"age1"},
{id:"id2",name:"name2",age:"age2"},
{id:"id3",name:"name3",age:"age3"}
]
json_object = students.each_with_object({}) do |hsh, returning|
returning[hsh[:id]] = hsh[:name]
end.to_json
In console:
puts json_object
=> {"id1":"name1","id2":"name2","id3":"name3"}
Your data is all identical, but if you wanted to generate a hash that took the value of students[n][:id] as keys and students[n][:name] as values you could do this:
student_ids_to_names = students.each_with_object({}) do |student, memo|
memo[student[:id]] = student[:name]
end
For your data, you'd end up with only one entry as the students are identical: { "id1" => "name1" }. If the data were different each key would be unique on :id.
Once you have a hash, you can call json_object = students_ids_to_names.to_json to get a JSON string.
I need to retrieve data from database column and put them to
[{1442507641,1},{1442507642,2},{1442507643,3},{1442507644,4}...]
format as the plot format requires.
I'm trying to do this by :
#data = TableName.where(:id => requiredid)
.map {|r| { r.received_date.to_i => r.value } }
but this returns format
data=[{1442507641=>6}, {1442507641=>7}, {1442507641=>5}, {1442507641=>6}, {1442507641=>5}, {1442507695=>9}, {1442507695=>9}, {1442507695=>7}, {1442507695=>8}]
How can I make the bracket as plot requires and remove the strange => ?
It seems like this ought to do what you're asking for:
parts = TableName.where(:id => requiredid).map do |r|
sprintf("{%d,%d}", r.received_date, r.value)
end
#data = "[#{parts.join(",")}]"
It's only for your options to manipulate your data:
#data = []
#data = User.where(:id => requiredid).map {|r| #data << "{#{r. received_date}, #{r.value}}"}
First you make #data as array. Than collect the string into array.
I have an API and a client app, and I am using rails with ActiveResource.
I have a Recruiter model that inherits from ActiveResource::Base
Let's say on the client side I write:
dave = Recruiter.new(email: "email#recruiter.com", password: "tyu678$--è", full_name: "David Blaine", company: "GE")
dave.save
The request I send is formatted like so:
{"recruiter":{
"email": "email#recruiter.com",
"password": "tyu678$--è",
"full_name": "David Blaine",
"company": "GE"
}
}
and the Json response I get from the API is formatted like:
{"recruiter":{
"email": "email#recruiter.com",
"password": "tyu678$--è",
"full_name": "David Blaine",
"company": "GE",
"foo": "bar"
},
"app_token":"ApfXy8YYVtsipFLvJXQ"
}
The problem is that this will let me access the app token with dave.app_token but I can't for instance write dave.foo, which raises an error.
Is there a way to flatten the response or read through it recursively si that I can access all of my instance's attributes while keeping the API response formatted as it is?
Looking through the whole ActiveResource process, you can overwrite the load method in your Recruiter model.
I just added the code in the #HACK section which "flatten" your attributes.
def load(attributes, remove_root = false, persisted = false)
raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
#prefix_options, attributes = split_options(attributes)
# HACK
if !attributes[:app_token].nil?
attributes[:recruiter]["app_token"] = attributes[:app_token]
attributes = attributes[:recruiter]
end
# /HACK
if attributes.keys.size == 1
remove_root = self.class.element_name == attributes.keys.first.to_s
end
attributes = ActiveResource::Formats.remove_root(attributes) if remove_root
attributes.each do |key, value|
#attributes[key.to_s] =
case value
when Array
resource = nil
value.map do |attrs|
if attrs.is_a?(Hash)
resource ||= find_or_create_resource_for_collection(key)
resource.new(attrs, persisted)
else
attrs.duplicable? ? attrs.dup : attrs
end
end
when Hash
resource = find_or_create_resource_for(key)
resource.new(value, persisted)
else
value.duplicable? ? value.dup : value
end
end
self
end