Rails, correct JSON body for a serialized field? - ruby-on-rails

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 => [])

Related

attr_accessor returns nil in model while returns the correct value in the controller

I have a model Assignment with attr_accessor :members
When I send my ajax request I can see in the terminal the params that are passed, and the my attr_accessor is well set "members"=>["", "12", "13"]
Here is an overview:
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"YfDZ8VHrrriXLgf2RRHdZtzE8X0V5NFrEOBKZmoCw5mbvqbNKBsUVdBeJSY6HCj4YqcTQi2iiYZFhXx3SYFngw==",
"assignment"=>{"members"=>["", "12", "13"], ....}
However in my model Assignment the value of members accessor returns always nil :
before_validation :check_members
def check_members
throw self.members # this throws: UncaughtThrowError (uncaught throw nil)
end
Why am getting nil for members instead the array of values ?
It seems that I needed to specify an "empty array" for the strong parameters, What I had before is this :
params.require(:assignment).permit(:title, :members)
I turned it to
params.require(:assignment).permit(:title, :members => [])
Now it's working :)
A related source : how to permit an array with strong parameters

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.

Rails - permit a param of unknown type (string, hash, array, or fixnum)

My model has a custom_fields column that serializes an array of hashes. Each of these hashes has a value attribute, which can be a hash, array, string, or fixnum. What could I do to permit this value attribute regardless of its type?
My current permitted params line looks something like:
params.require(:model_name).permit([
:field_one,
:field_two,
custom_fields: [:value]
])
Is there any way I can modify this to accept when value is an unknown type?
What you want can probably be done, but will take some work. Your best bet is this post: http://blog.trackets.com/2013/08/17/strong-parameters-by-example.html
This is not my work, but I have used the technique they outline in an app I wrote. The part you are looking for is at the end:
params = ActionController::Parameters.new(user: { username: "john", data: { foo: "bar" } })
# let's assume we can't do this because the data hash can contain any kind of data
params.require(:user).permit(:username, data: [ :foo ])
# we need to use the power of ruby to do this "by hand"
params.require(:user).permit(:username).tap do |whitelisted|
whitelisted[:data] = params[:user][:data]
end
# Unpermitted parameters: data
# => { "username" => "john", "data" => {"foo"=>"bar"} }
That blog post helped me understand params and I still refer to it when I need to brush up on the details.

Force ActiveResource to not convert complex object from JSON

The ActiveResource docs states that:
Any complex element (one that contains other elements) becomes its own object:
# With this response:
# {"id":1,"first":"Tyler","address":{"street":"Paper St.","state":"CA"}}
#
# for GET http://api.people.com:3000/people/1.json
#
tyler = Person.find(1)
tyler.address # => <Person::Address::xxxxx>
Since an attribute on the object I'm retrieving is a RGeo object that is supposed be be JSON, how do I request that this attribute is not converted. So the above would become:
tyler = Person.find(1)
tyler.address # => {"street":"Paper St.","state":"CA"}
TRy defining it as serialize Hash
class Person < ActiveRecord::Base
serialize :address, Hash
end
It will then treat address field as Hash
#object.address should return you, key value pair

array of strings to array of objects

My model is giving me an array of strings as json, and I need an array of objects for my api to function correctly on the client side. In my model I define the json as
def as_json(options={})
super(:only => [:price, :available, :location_id, :beer_id], :methods => [:name, :brewery, :style, :label_url, :description, :id])
end
This is giving me a response
{"available":"on","beer_id":1,"created_at":"2013-05-31T16:45:09Z","description":"Good","id":1,"location_id":1,"price":"3.0","size":"16.0","updated_at":"2013-05-31T16:45:09Z"}
which is obviously missing the [ ] indicating it is an array of objects. Is there a simple way to convert this array of strings into an array of objects?
EDIT: My original response which was working fine was
[{"available":"on","beer_id":1,"created_at":"2013-05-31T16:45:09Z","description":"Good","id":1,"location_id":1,"price":"3.0","size":"16.0","updated_at":"2013-05-31T16:45:09Z"}]
My ios app is crashing because it doesn't think the current response is of type NSDictionary because it is NSString. After looking around it appears that some change I made to the rails app changed the json response. The only clue I have is the missing brackets when I look at what was working and what is now not working.
As far as I can see, your response is not an array of strings, it's just a single JSON object.
If you need to convert the object into 1-element array of objects, just enclose it into [ and ]. :)

Resources