Rails Strong Parameters - POST a json array + one extra root field - ruby-on-rails

I am not sure what I am doing wrong here. I need to post an json object containing an array of objects + one extra root field. So for this code:
{
"root_field": "somedata",
"myobjects": [
{
"attr1": "1",
"attr2": 2",
"attr3": "3"
},
{
"attr1": "1",
"attr2": "2",
"attr3": "3"
}
]
}
I have this as code for strong parameters, which allows all myobjects in but fails to pass on the root_field, which is important in my application.
def my_params
params.require(:root_field)
params.require(:myobjects).map do |e|
ActionController::Parameters.new(e.to_hash).permit(:attr1,:attr2,:attr3)
end
end
Any thoughts?

If you want to while list root_field as a scalar value, it should be
params.permit(:root_field)
params.permit(:myobjects => [:attr1,:attr2,:attr3])

Related

Filter through nested JSON object and obtain JSON with specific keys, using Ruby

I currently have a nested JSON object which resembles
{
"People": [
{
"Name": "James",
"Age": "18",
"Gender": "Male",
"Sports": []
},
{
"Name": "Sarah",
"Age": "19",
"Gender": "Female",
"Sports": [
"Soccer",
"Basketball",
"Football"
]
}
]
}
Being new to Ruby, I aim to filter throught the entire json and return only the json object/objects in which the "Sports" array has content. So in the above scenario I expect to obtain the object below as a final outcome:
{
"Name": "Sarah",
"Age": "19",
"Gender": "Female",
"Sports": [
"Soccer",
"Basketball",
"Football"
]
}
Will I have to initiate a new method to perform such an act? Or would using regular ruby calls work in this case?
Although #philipyoo answer is right, it miss an explanation on how to "filter" the parsed JSON. If you are new to ruby, take a look at Array#keep_if : http://ruby-doc.org/core-2.2.0/Array.html#method-i-keep_if
require 'json'
people = JSON.parse("{long JSON data ... }")
people_with_sports = people.fetch('People', []).keep_if do |person|
!person.fetch('Sports', []).empty?
end
If you're getting a JSON object from a request, you want to parse it and then you can traverse the hash and arrays to find the information you need. See http://ruby-doc.org/stdlib-2.0.0/libdoc/json/rdoc/JSON.html
In your case, something like this:
require 'json'
parsed_json = JSON.parse('{"People": [ ... ]}')
parsed_json["People"].each do |person|
puts person if person["name"] == "Sarah"
end

Convert JSON into a Hash

I have this JSON and I am trying to send it to a Rails API from Postman:
{"object":
{
"type": "out",
"vars":
{
"x": "x",
"y": "y"
},
"values":
{
"ts": "timestamp",
"ok":
{
"total": 2,
"min": "x",
"max": "y"
},
"error":
{
"total": 2,
"error1": "first",
"error2": "second"
}
}
}
}
I need to convert this into a Hash in my model so that I can manipulate it with before_create. Here's what I came with:
object = self.to_json # => converts object to json
object = JSON.parse(object) # => converts json to hash
1st problem: I get this (id=>nil is not relevant since it will be inserted automatically in the database):
{"id"=>nil, "type"=>"out", "vars"=>{"x"=>"x", "y"=>"y"}, "values"=>{"ts"=>"timestamp", "ok"=>"{\"total\"=>2, \"min\"=>\"x\", \"max\"=>\"y\"}", "error"=>"{\"total\"=>2, \"error1\"=>\"first\", \"error2\"=>\"second\"}"}, "created_at"=>"2015-01-29T15:45:01.329Z", "updated_at"=>"2015-01-29T15:45:01.329Z"}
and when I try to manipulate object["values"]["ok"], Rails sends the error:
unexpected token at '"{\"total\"=\u003e2, \"min\"=\u003e\"x\", \"max\"=\u003e\"y\"}"'
2nd problem: I can only call object["values"], and I want to call it with a symbol, not a string object[:values].
Solved my issues using:
object = self.as_json.with_indifferent_access
# => allowing me to use a symbol key instead of a string
ok_vals = object[:values][:ok].as_json.gsub(/\=\>/, ':')
# => allowing to change json string '{"val1"=>"val1", "val2"=>"val2"}' to '{"val1":"val1", "val2":"val2"}'
ok_vals = JSON.parse(ok_vals)
# => which transform json string to hash {val1: "val1", val2: "val2"}
Feel free to make any suggestions to this code. Thanks for the help.

Parsing JSON hash with each generates "can't convert String into Integer"

I am parsing JSON from an API with the following code:
def json_test
content = open("API URL").read
json = JSON.parse(content)
json.each do |a|
puts a["first_name"]
end
end
The reason I'm using each is because the API request will return an array of hashes for multiple users, like this:
[{
"id": "1",
"first_name": "John"
},
{
"id": "2",
"first_name": "Bob"
}]
However, the API will return just a hash if the request only returns a single user, like thus:
{
"id": "2",
"first_name": "Bob"
}
This is where I'm getting the error message: can't convert String into Integer (TypeError)
I've been searching for a good way to be able to parse when it's not returning an array but just a hash and I'm stumped. Any pointers?
Array.wrap is designed just for this purpose.
Wraps its argument in an array unless it is already an array (or array-like).
Array.wrap({ a: 1 }) # => [{ a: 1 }]
Array.wrap [{ a: 1 }, { b: 2 }] # => [{ a: 1 }, { b: 2 }]
One way is putting it all inside a single element array and flattening it:
json = [JSON.parse(content)].flatten
If it is not an array, the flatten will be noop. If it is, the extra array layer will be removed.

Compare JSON structure in ruby

I have two json objects as below:
obj1= [ { "id": 4, "userId": "abc", "firstName": "abc", "lastName": "abc", "email": "abc#abc.it", "prefers" : [{"breakfast" : "bread" , "lunch" : "non-veg"}] } ]
obj2= [ { "id": 5, "userId": "def", "firstName": "def", "lastName": "def", "email": "def#def.it", "prefers" : [{"breakfast" : "egg" , "lunch" : "veg"}] } ]
Given these to objects i have to validate object2 has the same keys as in object1
diff(obj1,obj2) should give me missing keys
use keys to return an array of keys of the hash and then subtract them
obj1[0].keys - obj2[0].keys
# => array of missing keys
This Ruby JSON comparator will show you how to do it. It is designed to compare the two objects and return true if they're same, but from that you can devise a more complicated return value based on your needs.
If you only want true/false validation that the keys of both objects match, you can do:
object1.keys && object2.keys == object1.keys
That will give you a validation of matching or not.

How do I pretty print a hash to a Rails view?

I have something like:
{"a":"1","b":"2","c":"3","asefw":"dfsef"}
I want to print it out in a view. What's the best way to do that?
I tried parsing it as a JSON object and using JSON.stringify, but it seems to mess up indentation.
Any advice? I don't mind a JavaScript solution.
How about:
require 'json'
hash = JSON['{"a":"1","b":"2","c":"3","asefw":"dfsef"}']
puts JSON.pretty_generate(hash)
Which outputs:
{
"a": "1",
"b": "2",
"c": "3",
"asefw": "dfsef"
}
JSON.pretty_generate is more of a debugging tool than something I'd rely on when actually generating JSON to be sent to a browser. The "pretty" aspect also means "bloated" and "slower" because of the added whitespace, but it is good for diagnosing and comprehending what is in the structure so it might work well for your needs.
One thing to remember is that HTML, when rendered by a browser, has whitespace gobbled up, so whitespace runs disappear. To avoid that you have to wrap the JSON output in a <pre> block to preserve the whitespace and line-breaks. Something like this should work:
<pre>
{
"a": "1",
"b": "2",
"c": "3",
"asefw": "dfsef"
}
</pre>
irb(main)> puts queried_object.pretty_inspect
From PrettyPrint, so may need to require 'pp' first for this to work.
This also works great for e.g. Rails.logger output.
<%= raw JSON.pretty_generate(hash).gsub(" "," ") %>
If you (like I) find that the pretty_generate option built into Ruby's JSON library is not "pretty" enough, I recommend my own NeatJSON gem for your formatting.
To use it gem install neatjson and then use JSON.neat_generate instead of JSON.pretty_generate.
Like Ruby's pp it will keep objects and arrays on one line when they fit, but wrap to multiple as needed. For example:
{
"navigation.createroute.poi":[
{"text":"Lay in a course to the Hilton","params":{"poi":"Hilton"}},
{"text":"Take me to the airport","params":{"poi":"airport"}},
{"text":"Let's go to IHOP","params":{"poi":"IHOP"}},
{"text":"Show me how to get to The Med","params":{"poi":"The Med"}},
{"text":"Create a route to Arby's","params":{"poi":"Arby's"}},
{
"text":"Go to the Hilton by the Airport",
"params":{"poi":"Hilton","location":"Airport"}
},
{
"text":"Take me to the Fry's in Fresno",
"params":{"poi":"Fry's","location":"Fresno"}
}
],
"navigation.eta":[
{"text":"When will we get there?"},
{"text":"When will I arrive?"},
{"text":"What time will I get to the destination?"},
{"text":"What time will I reach the destination?"},
{"text":"What time will it be when I arrive?"}
]
}
It also supports a variety of formatting options to further customize your output. For example, how many spaces before/after colons? Before/after commas? Inside the brackets of arrays and objects? Do you want to sort the keys of your object? Do you want the colons to all be lined up?
For example, using your example Hash, you can get these different outputs, depending on what you want:
// JSON.neat_generate(o, wrap:true)
{
"a":"1",
"b":"2",
"c":"3",
"asefw":"dfsef"
}
// JSON.neat_generate o, wrap:true, aligned:true
{
"a" :"1",
"b" :"2",
"c" :"3",
"asefw":"dfsef"
}
// JSON.neat_generate o, wrap:true, aligned:true, around_colon:1
{
"a" : "1",
"b" : "2",
"c" : "3",
"asefw" : "dfsef"
}
You can try the gem awesome_print works very well, and in your view write
<%= ap(your_hash, plain: true, indent: 0).html_safe %>
also, you can change the values for config the styles to hash view
The given response is works fine, but if you want to have prettier and more custom pretty hash, use awesome_print
require 'awesome_print'
hash = JSON['{"a":"1","b":"2","c":"3","asefw":"dfsef"}']
ap hash
Cheers!
Pretty Print Hash using pure Ruby (no gems)
I came across this thread trying to solve this problem for myself.
I had a large Hash that I wanted to make pretty, but I needed to stay in ruby hash notation instead of JSON.
This is the code + examples
Use pretty_generate to get a nice formatted JSON string.
Replace all the JSON keys with symbol: equivalent
puts JSON.pretty_generate(result)
.gsub(/(?:\"|\')(?<key>[^"]*)(?:\"|\')(?=:)(?:\:)/) { |_|
"#{Regexp.last_match(:key)}:"
}
Sample JSON
{
"extensions": {
"heading": "extensions",
"take": "all",
"array_columns": [
"name"
]
},
"tables": {
"heading": "tables",
"take": "all",
"array_columns": [
"name"
]
},
"foreign_keys": {
"heading": "foreign_keys",
"take": "all",
"array_columns": [
"name"
]
},
"all_indexes": {
"heading": "all_indexes",
"take": "all",
"array_columns": [
"name"
]
},
"keys": {
"heading": "keys",
"take": "all",
"array_columns": [
"name"
]
}
}
Sample Ruby Hash
{
extensions: {
heading: "extensions",
take: "all",
array_columns: [
"name"
]
},
tables: {
heading: "tables",
take: "all",
array_columns: [
"name"
]
},
foreign_keys: {
heading: "foreign_keys",
take: "all",
array_columns: [
"name"
]
},
all_indexes: {
heading: "all_indexes",
take: "all",
array_columns: [
"name"
]
},
keys: {
heading: "keys",
take: "all",
array_columns: [
"name"
]
}
}

Resources