strong params JSON API specification - ruby-on-rails

I am working to an REST API in Rails 5.2 and I'm following the JSON API specification. My JSON are like this:
{
"data":{
"attributes":{
"name":"Gleydson",
"age":"30"
},
"relationships":{
"occupation":{
"data":{
"attributes": {
"name": "Teacher",
}
}
}
}
}
}
I have the following method user_params:
params.require(:data).require(:attributes)
.permit(:name, :age,
relationships: { occupation: { data: { attributes: [:name] } } })
but when I print the return of the method nothing is returned

Have you looked into using a gem to go from Ruby objects to JSON:API serialized ones. JSONAPI::Resources helps a lot with getting the params right since you just define a JSONAPI:Resource and tell it what to allow.
I think part of your problem is that in JSON:API the attributes and relationships keys are siblings
user_params: {data:{attributes:{name:x,age:y,relationships:{z}}}}
jsonapi is: {data:{attributes:{name:x,age:y},relationships:{z}}}

In the JSON API spec "attributes" and "relationships" are siblings.
In your example you have nested "relationships" inside of "attributes".
Instead try:
params.require(:data).permit({
attributes: [:name, :age],
relationships: {
occupation: {
data: {
attributes: [:name]
}
}
}
})

According to the spec, attributes should not show up under a relationship's data member. A relationship's data member is a resource identifier object, meaning it only (and must only) contain type and id.
For JSON:API compliance checking, you may want to check out the new ruby gem easy-jsonapi. It has a middleware and response validator that is super easy to use with intuitive error messages to tell you why your documents, requests, and responses are not compliant. It also pairs well with JSONAPI-SERIALIZER, which as #robertoplancarte was suggesting, could take your ruby objects and serialize them into JSON:API compliant JSON documents.

Related

Permitting array of hashes rails 5

My rails version is 5 and I have request param like this,
{ "segment": {
"name": "test",
"new_filters": [
{"criteria": "sad",
"other_keys": [{"key": "value"}]
},
{"criteria": "sad",
"other_keys1": [{"key1": "value1"}]
}]
}
}
I am stuck in permitting the new_filter params in rails controller,
I am trying below code,
params.require(:segment).permit(:name, :people_count, new_filters: [])
and still getting the error. But this is not the case while having array of strings in new_filter key.
Eg: ["sad", "asdasd"]. How to get the nested structure as whitelisted attribute?
This worked for me when testing with your attributes:
params.require(:segment).permit(:name, :people_count, new_filters: [:criteria, other_keys: [:key], other_keys1: [:key1]])
In your model file for segment try adding the line
accepts_nested_attributes_for :new_filters
this should allow you to pass those attributes.
https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Rails API: Cannot whitelist JSON field attribute

I'm building a rails API with a model containing an attribute data of JSON type. (PSQL)
But when I try to post something like this
{ model: { name: 'Hello', data: { a: 1, b: 2 } } }
Rails thinks a and b are the attributes of a nested data association... It considers then they are unpermitted params.
The thing is, { a: 1, b: 2 } is the value of my field data.
How to provide JSON value to an attribute ?
-
Edit:
The error displayed is:
Unpermitted parameters: name, provider, confidence, location_type, formatted_address, place_id, types, locality, ...
The value of the data attribute is { name: 'Name', provider: 'Provider', ... }
Like I said Rails thinks they are the attributes of a nested data association.
-
Log:
Pastebin
if the keys are unknown in advance this could be a workaround:
def model_params
data_keys = params[:model].try(:fetch, :data, {}).keys
params.require(:model).permit(data: data_keys)
end
Credit goes to aliibrahim, read the discussion https://github.com/rails/rails/issues/9454 (P.S seems like strong parameters will support this use case in Rails 5.1)
When you post something, you have to make sure that your json have the same parameters that your controller.
Example rails api:
def example
#model = Model.new(params)
#model.save
render(json: model.to_json, status: :ok)
end
def params
params.permit(:name, :provider, {:data => [:a, :b]})
end
Example front-end json for post:
var body = {
name: 'myName',
provider: 'provider',
data: {
a: 'something',
b: 'otherthing',
}
};
For some reason rails doesnt recognize a nested json, so you need to write into params.permit that data will be a json with that syntax, if where a array, the [] should be empty.

Allow an array of hashes with a dynamic hash (hstore) inside

I'm stuck with strong_parameters and this array of hashes with a dynamic hash (hstore) inside.
The structure is the following:
{ contact_sources: [
{ id: 1, filled_fields: { randomstuff: 'randomdata', dunno: 123 } },
{ id: 2, filled_fields: { blah: 'blabla', dunno: 9043 } }
] }
So, my main attempt is the following:
params.permit(contact_sources: [{:filled_fields => []}, 'id'])
Which doesn't return filled_fields. Any suggestion on how to deal with it?
Update 1:
I have the following model:
class ContactSource < ActiveRecord::Base
# Fields: id:integer, filled_fields:hstore
end
In my action, I'm submitting multiple records at once (mass update), so I have an array of contact_source, but actually they don't belong to anything, it's just a mass update.
Looks like it's not possible to do it with "plain" strong_parameters syntax. The only option you have is to actually, after filtering, re-add those values with a loop. I know it's terrible but it's the only way right now. I submitted a bug to Rails actually.

Rails, correct JSON body for a serialized field?

If I have a Rails model with a serialized field,
class Tournament < ActiveRecord::Base
serialize :prizes, Array
end
and I have the model available through a REST API, what is the correct format of the POST body?
I've tried the following in a Rspec test,
post :create, {
format: :json,
tournament: {
prizes: [
'z2000',
'z1000',
'z500',
'z250'
]
}
}
but this results in object with prizes set to blank.
Figure it out. The fix is completely unrelated to my JSON request body.
I had assigned my strong params in my controller as,
params.permit(:prizes)
But due to it being an array, I need the following
params.permit(prizes: [])
From https://github.com/rails/strong_parameters,
To declare that the value in params must be an array of permitted
scalar values map the key to an empty array:
params.permit(:id => [])

How to create a multi level document using MongoId

I am developing a Ruby on Rails (3.2.6) application and is using MongoId (3.0.0) to interact with the MongoDB database. I am just wondering how do save embeded JSON objects that contains multiple levels and not just one level.
I got an old MongoDB database with this and simular structure so I need to save new documents using the same structure.
This is from the documentation and is used to add a one level document:
Person.create(
first_name: "Heinrich",
last_name: "Heine"
)
How can I add an object with this structure:
{
"basic": {
"file_id": {
"file": "cf1952761a806c56c9bee60665418f02c"
},
"share": false,
"status": "created"
},
"data": {
"id": "4fd942dder5f5e88837300026e",
"name": "roberta",
"comment": "This is a comment"
}
}
The easiest way to do this is to create classes for basic and data and embed them in your top level document.
Embedded document classes are defined in Mongoid the same way as other documents with an embedded_in call and a matching embeds_one or embeds_many in the top level document.
The other option is to simply define a Hash field, but this obviously may have any structure.
Class Person
include Mongoid::Document
field :data, :type => Hash
...
end
:data will accept any hash, even with nested hashes.

Resources