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"}
Related
I am creating JSON output and want to check the value before I create the key value pair. Is there a way to do it while creating the JSON rather than adding it later?
I am creating this JSON output:
sample_json = {
abc: "abc",
xyz: "xyz",
pqr: some_value unless some_value.blank?
}
In this example I cannot check for unless some_value.blank? while creating the JSON string, so I first create the JSON and then add pqr: some_value separately after checking for a blank value, something like this:
sample_json = {
abc: "abc",
xyz: "xyz"
}
sample_json[:pqr] = some_value unless some_value.blank?
Is there is a way to add the check while creating the JSON itself like in the first example?
I don't think you can.
But, some other ways to deal with it, assuming you have active_support, you could use a hash compact (sample_json.compact), which will remove key-value pairs with nil values.
But If you do need !v.blank?, you could do:
sample_json.select { |_, value| !value.blank? }
I'd go about it like this:
require 'active_support/core_ext/object/blank'
require 'json'
some_value = 'foo'
hash = {
abc: "abc",
xyz: "xyz"
}
hash.merge!(pqr: some_value) unless some_value.blank?
puts hash.to_json
# >> {"abc":"abc","xyz":"xyz","pqr":"foo"}
If some_value = '' it'll result in:
# >> {"abc":"abc","xyz":"xyz"}
Don't create the JSON then try to change it. Instead create the base object, make the test then merge in the change, then serialize to JSON.
I am having problems accessing the attributes of my JSON data. Instead of accessing the JSON data it thinks it is a function.
#response = HTTParty.get('http://localhost:4000/test')
#json = JSON.parse(#response.body)
#json.each do |pet|
MyModel.create(pet) ! WORKS
puts "my object #{pet}" ! WORKS
puts "my object attribute #{pet.myattribute}" ! DOES NOT WORK
end
With no MethodError myattribute.
Thank you for any help!
You may be used to JavaScript, where both object.some_key and object["some_key"] do the same thing. In Ruby, a hash is just a hash, so you have to access values via object["some_key"]. A Struct in Ruby is similar to a JavaScript object, in that you can access values both ways, but the keys have to be pre-defined.
#json = JSON.parse(#response.body) returns a hash, so you would need to do
puts "my object attributes #{pet['id']}, #{pet['title']}"
you might want to convert to HashWithIndifferentAccess so you can use symbols instead of quoted strings, i.e.
#json = JSON.parse(#response.body).with_indifferent_access
# ...
puts "my object attributes #{pet[:id]}, #{pet[:title]}"
Lets say I have this Hash:
{
:info => [
{
:from => "Ryan Bates",
:message => "sup bra",
:time => "04:35 AM"
}
]
}
I can call the info array by doing hash[:info].
Now when I turn this into JSON (JSON.generate), and then parse it (JSON.parse), I get this hash:
{
"info" => [
{
"from" => "Ryan Bates",
"message" => "sup bra",
"time" => "04:35 AM"
}
]
}
Now if I use hash[:info] it returns nil, but not if I use hash["info"].
Why is this? And is there anyway to fix this incompatibility (besides using string keys from the start)?
The JSON generator converts symbols to strings because JSON does not support symbols. Since JSON keys are all strings, parsing a JSON document will produce a Ruby hash with string keys by default.
You can tell the parser to use symbols instead of strings by using the symbolize_names option.
Example:
original_hash = {:info => [{:from => "Ryan Bates", :message => "sup bra", :time => "04:35 AM"}]}
serialized = JSON.generate(original_hash)
new_hash = JSON.parse(serialized, {:symbolize_names => true})
new_hash[:info]
#=> [{:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}]
Reference: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#method-i-parse
In short, no. Think about it this way, storing symbols in JSON is the same as storing strings in JSON. So you cannot possibly distinguish between the two when it comes to parsing the JSON string. You can of course convert the string keys back into symbols, or in fact even build a class to interact with JSON which does this automagically, but I would recommend just using strings.
But, just for the sake of it, here are the answers to this question the previous times it's been asked:
what is the best way to convert a json formatted key value pair to ruby hash with symbol as key?
ActiveSupport::JSON decode hash losing symbols
Or perhaps a HashWithIndifferentAccess
I solved my similar issue with calling the with_indifferent_access method on it
Here I have a json string and we can assign it to variable s
s = "{\"foo\":{\"bar\":\"cool\"}}"
So now I can parse the data with the JSON class and assign it to h
h = JSON.parse(s).with_indifferent_access
This will produce a hash that can accept a string or a symbol as the key
h[:foo]["bar"]
#=> "cool"
Use ActiveSupport::JSON.decode, it will allow you to swap json parsers easier
Use ActiveSupport::JSON.decode(my_json, symbolize_names: true)
This will recursively symbolize all keys in the hash.
(confirmed on ruby 2.0)
It's possible to modify all the keys in a hash to convert them from a string to a symbol:
symbol_hash = Hash[obj.map{ |k,v| [k.to_sym, v] }]
puts symbol_hash[:info]
# => {"from"=>"Ryan Bates", "message"=>"sup bra", "time"=>"04:35 AM"}
Unfortunately that doesn't work for the hash nested inside the array. You can, however, write a little recursive method that converts all hash keys:
def symbolize_keys(obj)
#puts obj.class # Useful for debugging
return obj.collect { |a| symbolize_keys(a) } if obj.is_a?(Array)
return obj unless obj.is_a?(Hash)
return Hash[obj.map{ |k,v| [k.to_sym, symbolize_keys(v)] }]
end
symbol_hash = symbolize_keys(hash)
puts symbol_hash[:info]
# => {:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}
You can't use that option like this
ActiveSupport::JSON.decode(str_json, symbolize_names: true)
In Rails 4.1 or later, ActiveSupport::JSON.decode no longer accepts
an options hash for MultiJSON. MultiJSON reached its end of life and
has been removed.
You can use symbolize_keys to handle it.
Warning: It works only for JSON strings parsed to hash.
ActiveSupport::JSON.decode(str_json).symbolize_keys
I am trying to split a string, and output the different parts, whats the best practice for rails 3 ?
String: "book_page_title"
Seperator: "_"
I want to have book, page and title as seperate variables, so that
I can perform actions on them..
Any help is appreciated.
Also, I am having trouble finding good reference sites, with examples like PHP have, and suggestions ?
To split:
book,page,title = string.split('_')
And to recombine:
string = [book,page,title].join('_')
use
split('_')
method it gives array.
Try ruby+string+doc in google, you will get http://ruby-doc.org/core/classes/String.html as the first result, and you can see a number of string functions in this link. You can see split there.
splitted_array = "book_page_title".split("_")
=> ["book", "page", "title"]
splitted_array.each do |string|
#..do manipulations here
end
"book_page_title".split("_") will return you array of strings. So you can access every element via [].
splitted = "book_page_title".split("_") # ["book", "page", "title"]
puts splitted[0] # gives "book"
puts splitted[1] # gives "page"
puts splitted[2] # gives "title"
a = "book_page_title".split("_")
a.each do |i|
instance_variable_set("##{i}", "value")
end
#book #=> *value*
#page #=> *value*
#title #=> *value*
i am failing to render a json response in ruby on rails from a hash datastructure of country-names with their country-codes: { "AF"=>"Afghanistan", "AL"=>"Albania", "DZ"=>"Algeria", ... }, so that the json response has its entries alphabetically ordered like this:
{ "AF":"Afghanistan", "AL":"Albania", "DZ"=>"Algeria" ... }
the problem, for my understanding, is, that a ruby hash has in itself no notion of order. so the response is totally random.
thanks for any help!
martin
You can use ActiveSupport::OrderedHash
Sample Case:
hash = ActiveSupport::OrderedHash.new
hash["one"] = "one"
hash["two"] = "two"
hash["three"] = "three"
p hash # Will give you the hash in reverse order
p hash.to_json # Will give you a json with the ordered hash
How about an array of hashes like:
[{ "AF"=>"Afghanistan"}, {"AL"=>"Albania"}, {"DZ"=>"Algeria"}, ... ]
thanks to previous answers (-> westoque) i ended up to monkey patch the Hash Class in rails initializers folder like that:
class Hash
def to_inverted_ordered_hash
copy = self.dup.invert.sort
copy.inject(ActiveSupport::OrderedHash.new) {|hash, i| hash[i[1]] = i[0]; hash}
end
def to_ordered_hash
copy = self.dup.sort
copy.inject(ActiveSupport::OrderedHash.new) {|hash, i| hash[i[1]] = i[0]; hash}
end
end
and called to_json when rendered from the controller.
Thanks a lot!