array of strings to array of objects - ruby-on-rails

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 ]. :)

Related

ActionController::Parameters converts integer to string

I have defined user_params in rails 5, like this:
def training_plan_params
params.require(:training_plan).permit(
:training_plan_id,
:sport_id,
:distance,
lastTrainingStatus: [:duration,:reps,:type,:level],
trainings: [:text, :order, :level],
modified: [:level,:duration]
)
end
but when i send the params to rails, like this:
{ training_plan: { sport_id: 2, distance: 900 } }
it doesn't retrieve the distance in the controller as integer, like this:
=> <ActionController::Parameters {"sport_id"=>"2", "distance"=>"900"} permitted: true>
=> training_plan_params[:distance]
=> "900"
is there a way to keep its type and not converts it to string?
Was dealing with the same issue today, and I did some searching around.
I found this post: Rails test is converting my array of ints to an array of strings
Basically, the issue is with the way you're (we're) using ActionDispatch::IntegrationTest, not with ActionController::Parameters.
I solved this by converting the input to my PUT/POST call with .to_json and providing headers: { 'Content-Type': 'application/json' } to the PUT/POST call. That then led to the test router treating my data as json and preserving the typings, rather than defaulting to treating things as text.

How to store string as array in database column using Ruby on Rails

This question is asked many times on SO. The main problem is nothing got fits into my situation.
Case is, I am not able to store typed content as array in database column.
text_field whose code is:
= text_field_tag 'product[keywords][]', #product.keywords, class: 'tab-input
product_keywords'
In controller strong parameters are:
params.require(:product).permit(:id, :name, :keywords => [])
Jquery code that is not not removing value upon deletion when typed wrong value but it add commas after each element as I want to take commas seperated value in one column.
$(document).on 'keyup', '.product_keywords', ->
keyword = #value.replace(/(\w)[\s,]+(\w?)/g, '$1, $2')
if keyword != #value
#value = keyword
return
model code:
serialize :keywords, Array
migration code:
class AddKeywordsToProducts < ActiveRecord::Migration[5.1]
def change
add_column :products, :keywords, :text
end
end
So, if someone writes, abc and hit space a comma is added in the end. after three typed words it will look like:
abc, dbx, she
now I want to store it as array in column but its not storing properly.
it stores as:
["abc, dbx, she"]
Also please can anybody tell me the best cases to handle these cases?
Plus best practices to deal with such cases using ruby so I will learn it for future?
You probably want a custom serializer as shown here. So instead of:
serialize :keywords, Array
You might do somewhat like:
serialize :keywords, KeywordSerializer
And somewhere in helpers:
class KeywordSerializer
def self.dump(what)
what.join(", ")
end
def self.load(what)
what.split(/\s*,\s*/)
end
end
Passing array elements using single form tag is not possible to pass as a array and passing array as a string, you need to process it near white-listing your params,
permitted_params = params.require(:product).permit(:id, :name, :keywords => [])
permitted_params[:keywords] = permitted_params[:keywords][0].split(/\s*,\s*/)

Rails, strong parameters, and complex data structures

Good aftern, SO folks
I am strong parameterizing a Rails 3 application that we plan to upgrade to Rails 4. Some of the controllers use the params object to hold not just nested hashes, but hashes within arrays within hashes within arrays etc. Changing the nature of the data structure would be too intense, we want to ideally have it return the same data structure, but strong parameterized
Here's an example as JSON:
"my_example" => {
"options" =>
[{"id" => "1"
"name" => "claire"
"keywords" =>
["foo", "bar"]
},
{"id" => "2",
"name" => "marie",
"keywords =>
["baz"]
}],
"wut" => "I know, right?"
}
But for added fun, the keywords array can contain any string. Which I've read about and which is tricky and supported in other versions of rails but whatever.
Are there any general rules of thumb about making complex data structures with the strong_parameters gem? I know that Rails 4 and 5 handle this better, but I'm curious.
Nested parameters are not really that challenging.
params.require(:my_example)
.permit(:wutz, options: [:id, :name, keywords: []])
This expects that options is an array of resources where the keys :id, :name, and :keywords are to be whitelisted.
:wutz, :id, :name can be any permitted scalar type. keywords: [] permits an array of any scalar type (any string, integer, date, etc). I don't really get why you're fretting here.
The issue is mainly with nested hashes with extremely dynamic contents. In that case which is not quite covered the Rails strong parameters you can use .permit! and unleash the full tools of Ruby hash slicing and dicing which are quite formidable.
The gem pretty much backports the api of ActionController::Parameters in later versions of Rails pretty closely so I would not expect any major hickups when upgrading.
https://github.com/rails/strong_parameters#nested-parameters

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

Rails - Strong Parameters - Nested Objects

I've got a pretty simple question. But haven't found a solution so far.
So here's the JSON string I send to the server:
{
"name" : "abc",
"groundtruth" : {
"type" : "Point",
"coordinates" : [ 2.4, 6 ]
}
}
Using the new permit method, I've got:
params.require(:measurement).permit(:name, :groundtruth)
This throws no errors, but the created database entry contains null instead of the groundtruth value.
If I just set:
params.require(:measurement).permit!
Everything get's saved as expected, but of course, this kills the security provided by strong parameters.
I've found solutions, how to permit arrays, but not a single example using nested objects. This must be possible somehow, since it should be a pretty common use case. So, how does it work?
As odd as it sound when you want to permit nested attributes you do specify the attributes of nested object within an array. In your case it would be
Update as suggested by #RafaelOliveira
params.require(:measurement)
.permit(:name, :groundtruth => [:type, :coordinates => []])
On the other hand if you want nested of multiple objects then you wrap it inside a hash… like this
params.require(:foo).permit(:bar, {:baz => [:x, :y]})
Rails actually have pretty good documentation on this: http://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-permit
For further clarification, you could look at the implementation of permit and strong_parameters itself: https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/strong_parameters.rb#L246-L247
I found this suggestion useful in my case:
def product_params
params.require(:product).permit(:name).tap do |whitelisted|
whitelisted[:data] = params[:product][:data]
end
end
Check this link of Xavier's comment on github.
This approach whitelists the entire params[:measurement][:groundtruth] object.
Using the original questions attributes:
def product_params
params.require(:measurement).permit(:name, :groundtruth).tap do |whitelisted|
whitelisted[:groundtruth] = params[:measurement][:groundtruth]
end
end
Permitting a nested object :
params.permit( {:school => [:id , :name]},
{:student => [:id,
:name,
:address,
:city]},
{:records => [:marks, :subject]})
If it is Rails 5, because of new hash notation:
params.permit(:name, groundtruth: [:type, coordinates:[]]) will work fine.

Resources