I'm trying to send a JSON API response from my rails app to Dasheroo which expects the following format:
{
my_statistic: { type: 'integer', value: 1, label: 'My Statistic' }
}
However it is not happy with my data structure generated by the following code:
In controller:
def count_foo_members
#foo = Foo.all.count
end
In count_foo_members.json.jbuilder:
json.foo_members do
json.type 'integer'
json.value #foo
json.label 'Foo Members'
end
If I open this route in my browser I can see the following:
{
"foo_members":{"type":"integer","value":1,"label":"Foo Members"}
}
From the results above, the only thing that I can see that could have an effect on the result is the fact that my JSON result has quotation marks around the JSON Key values.
My question thus is: How can I remove these quotation marks in Rails 4 and JBuilder?
JSON.parse(you_response) and you get standart hash.
You cannot remove the quotation marks from the keys. The responsibility is on the consumer (Dasheroo) to parse your JSON string into a JavaScript Object, which will "remove" the quotes from the keys.
Read json-object-with-or-without-quotes for further practical insight.
Related
So i have a json here and im trying to search for name
I am trying to read through the whole json, and only match to name. But im not sure how to go about that.
I parsed the json below into a variable called jsondata
and created this loop here to read it.
jsondata.each do |links|
puts links
end
But how can i go about only reading the name field and matching it to a string? Lets say im looking looking for the word leo.
{"files":[{"name":"github.jpeg","size":10852,"deleteType":"DELETE","deleteUrl":"http://gifs.meow.me/github.jpeg","url":"http://gifs.meow.me/github.jpeg"},{"name":"leo.jpg","size":51678,"deleteType":"DELETE","deleteUrl":"http://gifs.meow.me/leo.jpg","url":"http://gifs.meow.me/leo.jpg"},{"name":"leo2.jpg","size":41407,"deleteType":"DELETE","deleteUrl":"http://gifs.meow.me/leo2.jpg","url":"http://gifs.meow.me/leo2.jpg"}]}
You can search each string under the key of "name" for the needle you're looking for using String#include? or String#index. The Enumerable method select would be a good choice for selecting only the hashes that contain the data you're looking for:
jsondata["files"].select{|h| h["name"].include? "leo" }
This presumes you have parsed the json data into a Ruby hash:
jsondata = {"files"=>[
{"name"=>"github.jpeg",
"size"=>10852,
"deleteType"=>"DELETE",
"deleteUrl"=>"http=>//gifs.meow.me/github.jpeg",
"url"=>"http=>//gifs.meow.me/github.jpeg"},
{"name"=>"leo.jpg",
"size"=>51678,
"deleteType"=>"DELETE",
"deleteUrl"=>"http=>//gifs.meow.me/leo.jpg",
"url"=>"http=>//gifs.meow.me/leo.jpg"},
{"name"=>"leo2.jpg",
"size"=>41407,
"deleteType"=>"DELETE",
"deleteUrl"=>"http=>//gifs.meow.me/leo2.jpg",
"url"=>"http=>//gifs.meow.me/leo2.jpg"}
]}
jsondata["files"].select{|h| h["name"].include? "leo" }
# => [{"name"=>"leo.jpg", "size"=>51678, "deleteType"=>"DELETE", "deleteUrl"=>"http=>//gifs.meow.me/leo.jpg", "url"=>"http=>//gifs.meow.me/leo.jpg"}, {"name"=>"leo2.jpg", "size"=>41407, "deleteType"=>"DELETE", "deleteUrl"=>"http=>//gifs.meow.me/leo2.jpg", "url"=>"http=>//gifs.meow.me/leo2.jpg"}]
jsondata.each do |link|
if link.name =~ /leo/
# do something
end
end
or
jsondata.each do |link|
if link.name.include? 'leo'
# do something
end
end
Using jsondata as defined by #Cam, you can do the following.
jsondata["files"].each_with_object({}) { |g,h|
h[g["name"]]=g["url"] if g["name"] =~ /\Aleo/ }
#=> {"leo.jpg"=>"http=>//gifs.meow.me/leo.jpg",
# "leo2.jpg"=>"http=>//gifs.meow.me/leo2.jpg"}
I have a Ruby on Rails JSON question.
I have what I think is a strange error. I have the following JSON string which I get like this from an external API
test = "[{'domain': 'abc.com'}, {'domain': 'def.com'}, {'domain': 'ghi.com'}]"
Now, I want to convert this string to a hash using:
hash = JSON.parse test
The problem is that it errors with:
JSON::ParserError: 419: unexpected token at '{'domain': 'abc.com'}, {'domain': 'def.com'}, {'domain': 'ghi.com'}]'
The problem now with just replacing ' with " is dangerous if any strings includes ' or ". Anyone have a solution?
It's most likely because this isn't valid JSON. Change your single quotes to double quotes, like so:
test = '[{"domain": "abc.com"}, {"domain": "def.com"}, {"domain": "ghi.com"}]'
An explanation can be found here, and you can validate your JSON here.
You're getting an error because your string isn't valid JSON. In JSON all property names must be double-quoted and string values must also be double-quotes. Single-quotes are never valid.
test = '[{"domain": "abc.com"}, {"domain": "def.com"}, {"domain": "ghi.com"}]'
JSON.parse(test)
# => [ { "domain" => "abc.com" },
# { "domain" => "def.com" },
# { "domain" => "ghi.com" } ]
Using Rails 4 or above, If you want to have symbol keys instead of string keys, you can use deep_symbolize_keys method
hash = JSON.parse(test).deep_symbolize_keys
That's in addition that the real problem was invalid json as MyCah mentioned.
Use this piece of code. you are missing ActiveSupport::JSON
ActiveSupport::JSON.decode json_string
I'm playing around with Netflix's Workflowable gem. Right now I'm working on making a custom action where the user can choose choices.
I end up pulling {"id":1,"value":"High"} out with #options[:priority][:value]
What I want to do is get the id value of 1. Any idea how to pull that out? I tried #options[:priority][:value][:id] but that seems to through an error.
Here's what the action looks like/how I'm logging the value:
class Workflowable::Actions::UpdateStatusAction < Workflowable::Actions::Action
include ERB::Util
include Rails.application.routes.url_helpers
NAME="Update Status Action"
OPTIONS = {
:priority => {
:description=>"Enter priority to set result to",
:required=>true,
:type=>:choice,
:choices=>[{id: 1, value: "High"} ]
}
}
def run
Rails.logger.debug #options[:priority][:value]
end
end
Here's the error:
Error (3a7b2168-6f24-4837-9221-376b98e6e887): TypeError in ResultsController#flag
no implicit conversion of Symbol into Integer
Here's what #options[:priority] looks like:
{"description"=>"Enter priority to set result to", "required"=>true, "type"=>:choice, "choices"=>[{"id"=>1, "value"=>"High"}], "value"=>"{\"id\":1,\"value\":\"High\"}", "user_specified"=>true}
#options[:priority]["value"] looks to be a strong containing json, not a hash. This is why you get an error when using [:id] (this method doesn't accept symbols) and why ["id"] returns the string "id".
You'll need to parse it first, for example with JSON.parse, at which point you'll have a hash which you should be able to access as normal. By default the keys will be strings so you'll need
JSON.parse(value)["id"]
I'm assuming the error is something like TypeError: no implicit conversion of Symbol into Integer
It looks like #options[:priority] is a hash with keys :id and :value. So you would want to use #options[:priority][:id] (lose the :value that returns the string).
I am new to Ruby, and I am having some problems with hashes.
I have XML returned from the YouTube API that I converted into a hash. Here is the hash returned by Hash.from_xml(): http://pastebin.com/9xxE6iXU
I am trying to grab specific elements from the hash for each result, such as the title, link, author, etc. Whenever I try to loop through the hash or grab a specific element, I receive a "can't convert String into Integer" error.
Here is the code I am using for the loop:
#data["feed"]["entry"]["title"].each do |key, value|
"<p>"+key+" "+value+"</p>"
end
I have also tried grabbing specific elements, such as #data["feed"]["entry"]["title"][0].
How do I loop through the hash and grab specific elements out?
That's happening because #data["feed"]["entry"] is array of hashes:
puts #data["feed"]["entry"].class # => Array
Each element-hash inside this array has "id", "category", "title" etc. values.
For grabbing each title try to use following snippet:
#data["feed"]["entry"].each do |entry|
puts entry["title"]
end
# => "TABE test adult basic education"
"WhatCollegesHopeYouWon'tFindOutAboutACTSATTestPrep..."
....
In my controller, the following works (prints "oké")
puts obj.inspect
But this doesn't (renders "ok\u00e9")
render :json => obj
Apparently the to_json method escapes unicode characters. Is there an option to prevent this?
To set the \uXXXX codes back to utf-8:
json_string.gsub!(/\\u([0-9a-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
You can prevent it by monkey patching the method mentioned by muu is too short. Put the following into config/initializers/patches.rb (or similar file used for patching stuff) and restart your rails process for the change to take affect.
module ActiveSupport::JSON::Encoding
class << self
def escape(string)
if string.respond_to?(:force_encoding)
string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
end
json = string.gsub(escape_regex) { |s| ESCAPED_CHARS[s] }
json = %("#{json}")
json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
json
end
end
end
Be adviced that there's no guarantee that the patch will work with future versions of ActiveSupport. The version used when writing this post is 3.1.3.
If you dig through the source you'll eventually come to ActiveSupport::JSON::Encoding and the escape method:
def escape(string)
if string.respond_to?(:force_encoding)
string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
end
json = string.
gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
gsub(/([\xC0-\xDF][\x80-\xBF]|
[\xE0-\xEF][\x80-\xBF]{2}|
[\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
}
json = %("#{json}")
json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
json
end
The various gsub calls are forcing non-ASCII UTF-8 to the \uXXXX notation that you're seeing. Hex encoded UTF-8 should be acceptable to anything that processes JSON but you could always post-process the JSON (or monkey patch in a modified JSON escaper) to convert the \uXXXX notation to raw UTF-8 if necessary.
I'd agree that forcing JSON to be 7bit-clean is a bit bogus but there you go.
Short answer: no.
Characters were not escaped to unicode with the other methods in Rails2.3.11/Ruby1.8 so I used the following:
render :json => JSON::dump(obj)
That is the correct encoding. JSON doesn't requre Unicode characters to be escaped, but it is common for JSON libraries to produce output which contains only 7-bit ASCII characters, to avoid any potential encoding problems in transit.
Any JSON interpreter will be able to consume that string and reproduce the original. To see this in action, just type javascript:alert("ok\u00e9") into your browser's location bar.
render :json will call .to_json on the object if it's not a string. You can avoid this problem by doing:
render :json => JSON.generate(obj)
This will by pass a string directly and therefore avoid the call to ActiveSupport's to_json.
Another approach would be to override to_json on the object you are serializing, so in that case, you could do something like:
class Foo < ActiveRecord::Base
def to_json(options = {})
JSON.generate(as_json)
end
end
And if you use ActiveModelSerializers, you can solve this problem by overriding to_json in your serializer:
# controller
respond_with foo, :serializer => MySerializer
# serializer
attributes :bar, :baz
def to_json(options = {})
JSON.generate(serializable_hash)
end
I have got a very tricky way to solve this problem. Well, if to_json did not allow you to have the correct code, then you could directly try to write :
render text: tags
render json: tags or render json: tags.to_json will always auto transfer the encoding style, but if you use render text:tags, then the string will stay as it is. And I think jQuery could still recognize the data.