Rails has_many input from Angular2 front end won't save - ruby-on-rails

I'm building an Angular 2 front-end app that's getting data from a Rails 5 API. It's a kind of network inventory app.
I've got a Asset-form in Angular2 and there's an multi-select input for the ip_addresses of the asset.
I'm unable to get Rails to accept this data in the back-end.
The asset object:
{"name":"SERVER_A","serial":"XOR-354","location_id":1,"asset_type_id":1,"model_id":3,"ip_address_ids":[5304,5305]}
Here's my asset.service.ts:
createAsset(asset: Asset){
let formData = new FormData();
for(var key in asset){
if(key == "ip_address_ids") {
for (var i = 0; i < asset[key].length; i++) {
formData.append("asset["+key+"][]", JSON.stringify(asset[key][i]));
console.log("asset["+key+"][]", JSON.stringify(asset[key][i]));
}
}
if(key != "id") {
formData.append("asset["+key+"]", asset[key]);
}
}
let headers = new Headers();
let authToken = localStorage.getItem('auth_token');
headers.append('Authorization', authToken);
return this.http.post(this.assetUrl, formData, { headers })
.map((response: Response) => response.json());}
This is what im getting in the Rails server console:
Started POST "/assets" for ::1 at 2017-02-06 13:58:33 +0100
Processing by AssetsController#create as HTML
Parameters: {"asset"=>{"name"=>"SERVER_A", "description"=>"undefined",
"serial"=>"XOR-354", "asset_tag"=>"undefined",
"firmware"=>"undefined", "ssh"=>"undefined", "telnet"=>"undefined",
"http"=>"undefined", "location_id"=>"1", "asset_type_id"=>"1",
"model_id"=>"3", "prtg_id"=>"undefined", "ticket_id"=>"undefined",
"ip_address_ids"=>"5304,5305"}}
Unpermitted parameter: ip_address_ids
I've permitted the param of ip_address_ids
def asset_params
params.require(:asset).permit(:name, :description, :serial, :asset_tag, :firmware, :ssh, :telnet, :http, :location_id, :asset_type_id, :model_id, :prtg_id, :ticket_id, :ip_address_ids => [])
end
The strange thing is that if I use the Advanced REST Client in Chrome It's successful.
Here's an image of the REST Client
The result in the Rails server console:
Started POST "/assets" for ::1 at 2017-02-06 14:04:42 +0100
Processing by AssetsController#create as HTML
Parameters: {"asset"=>{"name"=>"Test", "asset_type_id"=>"2", "location_id"=>"33", "model_id"=>"4", "ip_address_ids"=>["5213", "5214"]}}
I think that the problem is that Angular sends the IDs as a string and the REST Client sends the IDs as an Array of strings.
Any idea on how to fix this?

Your ip_address_ids params is being passed as string, rather than array, why not use formData = JSON.stringify({asset: asset}) instead of custom processing?
If the case is that you want to pass it as an actual string you should not permit it with => [], only :ip_address_ids would be enough.

Related

Null is equal to string

Im using Angular + ts.
My request looks like:
getOrders(this.value.id, null, null).subscribe((s) => {
this.ordersArray = s
})
For some reason. null is converted to "null" on the server, what could be the reason for this?
backend console
Started GET "/admin/api/as_supplier/orders.json?start=null&end=null" for ::1 at 2022-04-19 11:01:32 +0300
Processing by Admin::Api::AsSupplier::OrdersController#index as JSON
Parameters: {"start"=>"null", "end"=>"null"}
Completed 500 Internal Server Error in 30ms (ActiveRecord: 0.0ms)
Or is the problem not on the frontend, but on the backend?
upd:
public getOrders(supplierId?: any, start?: any, end?: any): Observable<IOrders> {
return this.http
.get<IOrders>(`${environment.apiUrl}/admin/api/as_supplier/orders.json`, {
params: {
start,
end
}
})
.pipe(tap(response => this.orders = response))
}
you should do something like this:
let params = new HttpParams();
if (start !== null && start !== undefined) {
params = params.set('start', start);
}
if (end !== null && end !== undefined) {
params = params.set('end', end);
}
return this.http.get<IOrders(`${environment.apiUrl}/admin/api/as_supplier/orders.json`, {params})
#Alex i think the problem in your server side, try to parse params before you use it in the rest of your code in API

Parsing JSON POST data sent from Unity to Ruby On Rails

I'm building a Rails service for a Unity front end. One of the controllers is having an issue parsing the JSON blob from my UnityWebRequest. Here is what Unity says it is sending:
[StoryPost] Sending request to localhost:3000/stories/new with post data [words, {"_array":[{"_text":"mailing"}]}]
And here is what Rails is logging when it receives the JSON:
Started POST "/stories/new" for 127.0.0.1 at 2017-08-26 20:08:40 -0400
Error occurred while parsing request parameters.
Contents:
words=%7B%22_array%22%3A%5B%7B%22_text%22%3A%22mailing%22%7D%5D%7D
ActionDispatch::Http::Parameters::ParseError (743: unexpected token at 'words=%7B%22_array%22%3A%5B%7B%22_text%22%3A%22mailing%22%7D%5D%7D'):
actionpack (5.1.3) lib/action_dispatch/http/parameters.rb:113:in `rescue in parse_formatted_parameters'
actionpack (5.1.3) lib/action_dispatch/http/parameters.rb:107:in `parse_formatted_parameters'
It looks like I have some sort of encoding error. This started happening once I added the following code to my web request:
_request.SetRequestHeader("Content-Type", "application/json");
_request.SetRequestHeader("Accept", "application/json");
If I comment out the two SetRequestHeader calls mentioned above, then here is what Rails logs:
Started POST "/stories/new" for 127.0.0.1 at 2017-08-26 23:13:14 -0400
Processing by StoriesController#new as */*
Parameters: {"words"=>"{\"_array\":[{\"_text\":\"inspectors\"}]}"}
I added this code so that Rails would automatically know to parse my POST data as JSON. Anyone seen this type of issue before? New to Rails and HTTP, but not to Unity.
Relevant Code
For reference, here is my Rails Controller:
class StoriesController < ApplicationController
def new
post_data = params["words"]
words_array = post_data["_array"];
puts "words " + words_array
story = Story.new(words_array)
story.save()
end
end
And here is my Unity code. Note: _PostData is a Dictionary<string, string>.
protected ServiceCall()
{
switch (_Type)
{
case RequestType.Get:
_request = UnityWebRequest.Get(_URL);
break;
case RequestType.Post:
_request = UnityWebRequest.Post(_URL, _PostData);
break;
default:
throw new NullReferenceException("Unknown request type " + _Type);
}
_request.SetRequestHeader("Content-Type", "application/json");
_request.SetRequestHeader("Accept", "application/json");
_request.downloadHandler = new DownloadHandlerBuffer();
Diag.Crumb(this, $"Sending request to {_URL} with post data {_PostData.Pretty()}");
_requestOperation = _request.Send();
}
Here is how I am building _PostData
protected override Dictionary<string, string> _PostData
{
get
{
var asArray = new JsonArray<Word>(Luke.GuessWords);
string json = JsonUtility.ToJson(asArray);
return new Dictionary<string, string>{{"words", json}};
}
}
JSONArray is just a simple class that has an _array field, because Unity's JsonUtility cannot serialize top-level arrays.
In response to the feedback that my entire POST body was not formatted as JSON, I instead changed _PostData to return a string, and in my deriving classes serialized _PostData to JSON. Then in the base class, I encoded the JSON as bytes and sent it up as the POST body. Here is my changed code:
In Rails:
def new
words_array = params["_array"]
puts "words " + words_array.to_s
story = Story.new(words_array)
puts "story is " + story.to_s
end
In Unity:
protected override string _PostData
{
get
{
var asArray = new JsonArray<Word>(Luke.GuessWords);
string json = JsonUtility.ToJson(asArray);
return json;
}
}
And...
case RequestType.Post:
_request = UnityWebRequest.Post(_URL, new Dictionary<string, string>());
_request.uploadHandler = new UploadHandlerRaw
(
Encoding.UTF8.GetBytes(_PostData)
);
break;

Dart: Get POST parameters on server side

I send some data from client side using POST request
var value = new Map<String, String>();
value["param1"] = 'value1';
value["param2"] = 'value2';
value["param3"] = 'value3';
HttpRequest.postFormData('http://localhost:8080/', value);
and try to get this data on the server side:
HttpServer.bind(InternetAddress.ANY_IP_V6, 8080).then((server) {
server.listen((HttpRequest request) {
//TODO: process POST request
});
});
But how can I get POST values from the request as Map< string, string>?
upd 1
But as I see result of
var jsonString = await request.transform(UTF8.decoder).join();
depends on type of post message. If I change it result will be
multipart/form-data
------WebKitFormBoundaryoQQD7N0iA5zS8qmg
Content-Disposition: form-data; name="param1"
value 1
------WebKitFormBoundaryoQQD7N0iA5zS8qmg
Content-Disposition: form-data; name="param2"
value 2
------WebKitFormBoundaryoQQD7N0iA5zS8qmg
Content-Disposition: form-data; name="param3"
value 3
------WebKitFormBoundaryoQQD7N0iA5zS8qmg--
text/plain
param1=value 1
param2=value 2
param3=value 3
application/x-www-form-urlencoded
param1=value+1&param2=value+2&param3=value+3
As I have already asked how can I convert it to Map< string, string>?
Here is a complete tutorial https://www.dartlang.org/docs/tutorials/httpserver/#handling-post
String jsonString = await request.transform(UTF8.decoder).join();
or
Map result = await request.transform(UTF8.decoder).join().then(JSON.decode);
I have the same question, and I didn't find any solution until now. I need to pass a map from client to server, and server to use that map to interrogate a mongodb database. Client send that map, but server receive a string. Any conversion to json return also string, not a map.
On the client side I send a map named query:
await HttpRequest.postFormData('http://localhost:8085/$_coll',query).then((HttpRequest response)
On the server side :
if (request.method == 'POST') {
query = await request.transform(utf8.decoder).join();
}
I've tried to encode/decode to json, but with no success.

Slow query performance fetching keyword taxons in Spree extension

I'm working on adding functionality to an existing Spree custom photo printing store to allow photographers to upload their portfolios and sell photos through the site. I created a select2 text field for adding keywords to products using Spree::Taxon(s), and it works fine. I have fields for adding keywords in each language that the site supports (English and French).
However, the ajax query takes an extremely long time to complete (5-15s on average). The ActiveRecord query takes between 5-150ms to complete, and the view rendering takes no more than 60ms to complete. I can't account for the rest of the load time. Does anyone have advice on speeding up returning the result or what could be behind the extra time it takes to complete?
Using MySQL for the database, Ruby 2.2.1 and Rails 4.2.1. My dev environment is: Mac Mini (8gb ram, HDD), Aptana Studio IDE, server running on localhost:3000.
Please don't hesitate to request more clarifying information! I wasn't sure exactly what I needed to post to help with the context of my issue.
Controller to return JSON for the ajax request:
class KeywordTagsController < Spree::StoreController
respond_to :json
def find_keywords
term = params[:q]
Rails.logger.debug params.inspect
if params[:locale_str]
query = []
query = ["spree_taxons.name like ?", term + '%'] if term
locale = params[:locale_str].to_sym
keyword_taxonomy = Spree::Taxonomy.find_by(name: Spree.t("pi-taxonomy-keyword"))
keyword_taxons = keyword_taxonomy.taxons.with_translations(locale).where(query).order('name asc').select{ |t| t.parent_id != nil} if locale
respond_with keyword_taxons if keyword_taxons
end
end
end
Select2 initializer Javascript:
$("#keywords_en").select2({
createSearchChoice: function(term, data) {
if ($(data).filter(function() {
return this.text.localeCompare(term) === 0;
}).length === 0) {
return {
id: term,
text: term
};
}
},
multiple: true,
ajax: {
url: '/keywords/en',
dataType: 'json',
data: function (params) {
return {
q: params // search term
};
},
results: function(data){
return { results: $.map( data, function (keyword, i) {
return {id: keyword.id, text: keyword.name }
})}
}
},
tags: true,
tokenSeparators: [','],
placeholder: '<%= Spree.t('pi-keywords-placeholder-en') %>',
initSelection: function (element, callback) {
var data = [];
function splitVal(string, separator) {
var val, i, l;
if (string === null || string.length < 1) return [];
val = string.split(separator);
for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
return val;
}
$(splitVal(element.val(), ",")).each(function () {
data.push({
id: this,
text: this
});
});
callback(data);
}
});
Some console output for the request (some of the faster examples):
15:00:51 INFO: Processing by KeywordTagsController#find_keywords as JSON
15:00:51 INFO: Parameters: {"q"=>"", "_"=>"1436986845195", "locale_str"=>"fr"}
15:00:54 INFO: Completed 200 OK in 2870ms (Views: 40.6ms | ActiveRecord: 5.2ms)
15:33:45 INFO: Started GET "/keywords/fr?q=mer&_=1436986845196" for 127.0.0.1 at 2015-07-15 15:33:45 -0400
15:33:48 INFO: Processing by KeywordTagsController#find_keywords as JSON
15:33:48 INFO: Parameters: {"q"=>"mer", "_"=>"1436986845196", "locale_str"=>"fr"}
15:33:50 INFO: Completed 200 OK in 2136ms (Views: 5.4ms | ActiveRecord: 113.4ms)
15:33:58 INFO: Started GET "/keywords/fr?q=&_=1436986845197" for 127.0.0.1 at 2015-07-15 15:33:58 -0400
15:33:58 INFO: Processing by KeywordTagsController#find_keywords as JSON
15:33:58 INFO: Parameters: {"q"=>"", "_"=>"1436986845197", "locale_str"=>"fr"}
15:34:00 INFO: Completed 200 OK in 1885ms (Views: 38.7ms | ActiveRecord: 4.6ms)
It turns out that fetching the query results was only slow because I was in the dev environment. In production, it works at the speed one would expect. I'm posting this answer in case others have the same question!

Can't send complex json data to server using prototype and rails

I'm trying to send the following data to the server but at the server side I don't see the json parameter that I'm sending. Can anyone tell me what I'm doing wrong?
Below you can see the code.
Prototype:
send_data_url = "change"
hash = $H({"blocks": [{"h": "2", "area": [{"width": "96%", "els": [{"title": "first", "mand": true}, {"title": "second", "mand": false}]}]}]});
var request_array_json = hash.toJSON();
new Ajax.Request(send_data_url, {
method: 'post',
parameters: request_array_json,
contentType: 'application/json;'
});
Rails:
def change()
debugger
my_json = ActiveSupport::JSON.decode(params["_json"])
end
In the controller I see that the params object does not have the json parameter.
It only shows the action and the controller:
{"action"=>"change", "id"=>nil, "controller"=>"default/test"}
Note: I'm using prototype 1.6 qnd rails 2.3.2.
I found a solution using a plugin called json_request.
To get this working nicely, I also wrapped Ajax.Request with a new class that can send complex JSON objects. Example code:
Ajax.JSON = Class.create(Ajax.Request, {
initialize: function($super, url, options) {
options = options || {};
options.contentType = ‘application/x-www-form-urlencoded’;
options.postBody = Object.toJSON(options.object);
$super(url, options);
}
});
new Ajax.JSON(url, { object: myObject });
Read more: http://labnotes.org/2007/12/11/json_request-handling-json-request-in-rails-20/comment-page-1/#comment-143190#ixzz0n5iKnO60

Resources