Send a CSV file from Ember Js to Rails using Ajax - ruby-on-rails

I'm trying to upload a csv file with ajax from Ember Js and read it in my Rails application.
I've tried two different approaches. In the first one I tried to send the file from Ember like this:
submitImport() {
var fd = new FormData();
var file = this.get('files')[0];
fd.append("csv_file", file);
return this.get('authAjax')
.request('/contacts/import/csv', {
method: 'POST',
processData: false,
contentType: false,
data: fd
});
}
but the problem is that I don't get the csv_file param in the rails application. The request.content_type is application/x-www-form-urlencoded and I need multipart form. I could use reques.raw_post but then I get something like this ------WebKitFormBoundarymgBynUffnPTUPW3l\r\nContent-Disposition: form-data; name=\"csv_file\"; filename=\"elevatr_import.csv\"\r\nContent-Type: text/csv\r\n\r\ngeorgica,gica#me.com\nleo, leonard#yahoo.com\ngigel, becali#oita.fcsb\n\r\n------WebKitFormBoundarymgBynUffnPTUPW3l--\r\n and I would need to somehow parse this, and I don't really like this solution.
The other approach was to send the file base64 encoded and then decode it from Rails. I've tried this:
`
submitImport() {
var fd = new FormData();
var file = this.get('files')[0];
this.send('getBase64', file);
var encoded_file = this.get('encoded_file');
return this.get('authAjax')
.request('/contacts/import/csv', {
method: 'POST',
data: { csv_file: encoded_file }
});
},
getBase64(file) {
var controller = this;
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
controller.set('encoded_file', reader.result);
};
}
But for some reason, the post request is submitted first and only after that the getBase64 method is called.
Does anyone knows why is this happening or if I should use a different approach?
Thanks

FormData
To send using multipart/form-data, you have the right idea and are setting the correct options, but it's possible that authAjax or something else is setting options that are causing a conflict, resulting in a content-type of application/x-www-form-urlencoded.
// this should make a request with a content-type of multipart/form-data
$.ajax({
url: 'upload/destination',
type: 'POST',
data: formDataObj,
contentType: false,
processData: false,
});
Base64
The reason your file is read after your request is made is that FileReader works asynchronously. To send as a base64 encoded string, you'll need to wait for the reader to complete before initiating your ajax request. You can do that by making your request after the onloadend event.
actions: {
submitImport() {
var file = this.get('files')[0];
this.encodeAndSendFile(file);
},
},
sendFile(base64File) {
return this.get('authAjax')
.request('/contacts/import/csv', {
method: 'POST',
data: { csv_file: encoded_file },
});
},
encodeAndSend(file) {
var controller = this;
var reader = new FileReader();
reader.onloadend = function () {
controller.sendFile(reader.result);
};
reader.readAsDataURL(file);
}

Related

How to send 400KB video back to server on "onpagehide" call

Issue
I have a MediaRecorder video of up to 400 KB that I need to send to the server.
I want to be able to also send the video when someone exits the page.
My code looks kind of like this:
window.onpagehide = (e) => {
e.preventDefault();
var blob = new Blob(this.data, {type: "video/mp4"});
var file = new File([blob], "recording");
var formData = new FormData();
formData.append("recording", file);
axios.post('my-site-url', formData)
.then(function (response) {
if(response.data.result) {
console.log("email has been sent")
} else {
console.log("failed to send email")
}
})
.catch(({response}) => {
console.log("an error occured during email call");
console.error(response);
})
return null;
}
However window.onpagehide doesn't allow async functions so axios.post isn't running at all.
NB: this issue is tested only on IOS Safari.
For Chrome and Edge I am using onbeforeunload and it works fine
Question
What synchronous axios.post alternative can I use for this scenario?
What I tried
navigator.sendBeacon
It looked pretty promising, but it has a limit of 64KB, so I couldn't rely on it.
fetch
fetch('my-site-url', {
method: 'POST',
body: formData
});
error message:
Fetch API cannot load my-site-url due to access control checks.
ajax
$.ajax({
type: 'POST',
async: false,
url: "my-site-url",
data: formData,
processData: false,
timeout: 5000,
});
error message:
XMLHttpRequest cannot load my-site-url due to access control checks.
XMLHttpRequest
var request = new XMLHttpRequest();
request.open('POST', 'my-site-url', false);
request.send(formData);
if (request.status === 200) {
console.log("success!");
}
error message:
XMLHttpRequest cannot load my-site-url due to access control checks.
But these are not CORS related issues, as they only happen when inside onpagehide on Safari.

Passing FormCollection and FormData to controller [duplicate]

This question already has answers here:
How to append whole set of model to formdata and obtain it in MVC
(4 answers)
Closed 7 years ago.
$("#btn2").click(function () {
var data = new FormData();
var Form = $("#form2").serialize();
var send = {FormData+&+ data};
$.ajax({
url: '#Url.Action("AddProduct", "Product")',
data: send,
cache: false,
contentType: false,
processData: false
});
});
How to send FormData and Form object through ajax, please check the code its not working but it will tell you what I want to achieve
And also please mention how to receive this in Controller.
Basically I want to send picture and formcollection to my controller
Thanks
$("#btn2").click(function () {
var data = new FormData($('.form').get(0));
$.ajax({
url: '#Url.Action("AddProduct", "Product")',
type: 'POST',
data: data,
cache: false,
contentType: false,
processData: false
});
});
Through googling I got this code but my controller still receiving null??
Controller
public void AddProduct(Product product, HttpPostedFileBase myImage){}
You can use form.serialize to send data to your controller.
$(document).ready( function() {
var form = $('#form2');
$.ajax( {
type: "POST",
url: form.attr( 'action' ),
data: form.serialize(),
success: function( response ) {
console.log( response );
}
} );
} );

Ajax not allowing View rendering

I have a couple of variations on the ajax depending on the flow of interactions on the page. But it's only the variables that changes. here is one of them:
$('#btn_skickaEnkel').bind('click', function () {
$.ajax({
type: 'POST',
url: '/Contact/IntresseAnmälan/',
dataType: 'json',
data: {
Namn: $('#namn').val(),
Mail: $('#mail').val(),
Info: $('#meddelande').val(),
Nivå: $('#nivå').find(":selected").text(),
IsEnkel: true,
Telefon: $('#nr').val(),
ID: function () {
var url = window.location.pathname;
var id = url.substring(url.lastIndexOf('/') + 1);
return id;
}
},
traditional: true
});
});
In my controller i am unable to redirect or return a different view. At this point the data from JSON is no longer relevant because it's already been saved to DB.
My Controller:
public ActionResult IntresseAnmälan(BokningContainer bokning)
{
db = new DbContext();
//Saving some data to database(removed)
//Just determening the state of container obj.
if (bokning.IsEnkel)
{
//Geting som information from db (removed)
//Creating a mail (removed)
email.Send(bokning.Namn, bokning.Mail, body);
}
else
{
}
//db.SaveChanges();
//This part is not working, I think it's beacuase of the Ajax
return View("IntresseAnmälan");
}
The view is not rendered and I think it's related to the ajax. The view is simply not rendered. Is there some way to force returning it and ignoring the ajax? As I said the data is no longer needed because the content is already saved to the DB.
You cannot render view on ajax call,simply you can use form post method or just redirect it to desired action on "succcess" of ajax call as below:
$('#btn_skickaEnkel').bind('click', function () {
$.ajax({
type: 'POST',
url: '/Contact/IntresseAnmälan/',
dataType: 'json',
data: {
Namn: $('#namn').val(),
Mail: $('#mail').val(),
Info: $('#meddelande').val(),
Nivå: $('#nivå').find(":selected").text(),
IsEnkel: true,
Telefon: $('#nr').val(),
ID: function () {
var url = window.location.pathname;
var id = url.substring(url.lastIndexOf('/') + 1);
return id;
}
},
traditional: true,
success: function(result) {
window.location.href = '#Url.Action("action", "Controller")';
}
});
});
I couldn't believe my eyes when I figured out this "Bugg". The problem was that I, at some point, changed the submit to a button. So the form was never submiting. Well, at least I learnt a bit about views and Ajax.
Sorry for taking your time.

Parameters to dojo.xhrPost

When I use dojo.xhrGet , I use it this way to send more than one parameter via the GET
dojo.xhrGet
({
url:"MyServerPageURL?Param_A="+"ValueA"+"&Param_2="+"Value2",
load: function(data)
{
//do something
},
preventCache: true,
sync: true,
error: function(err)
{
alert("error="+err);
}
});
How could I do similar thing (send more than one parameter) when I have to use the dojo.xhrPost instead?
You do not want to use postData parameter unless you want to send a raw POST string. You normally want to use the 'content' parameter. For example:
dojo.xhrPost({
url: 'http://whatever...',
contents: {
ParamA: 'valueA',
ParamB: 'valueB'
},
load: function(response) {
// ...
}
});
Note: Use 'contents' works for xhrGet also, eliminating the need to build up the query string yourself and append to the URL.
Try to use postData parameter.
E.g:
var myParameters= {"Param_A":"Value_A", "Param_B":"Value_B"};
var xhrArgs = {
url: "postIt",
postData: dojo.toJson(myParameters),
handleAs: "text",
headers: { "Content-Type": "application/json", "Accept": "application/json" },
load: function(data) {
},
error: function(error) {
}
}
var deferred = dojo.xhrPost(xhrArgs);
For xhrPOst, it's possible to mention the form name to be posted. thus all your form elements get posted. If you want to pass some additional parameter then use hidden variable in the form that is posted.

Sending String Data to MVC Controller using jQuery $.ajax() and $.post()

There's got to be something I'm missing. I've tried using $.ajax() and $.post() to send a string to my ASP.NET MVC Controller, and while the Controller is being reached, the string is null when it gets there. So here is the post method I tried:
$.post("/Journal/SaveEntry", JSONstring);
And here is the ajax method I tried:
$.ajax({
url: "/Journal/SaveEntry",
type: "POST",
data: JSONstring
});
Here is my Controller:
public void SaveEntry(string data)
{
string somethingElse = data;
}
For background, I serialized a JSON object using JSON.stringify(), and this has been successful. I'm trying to send it to my Controller to Deserialize() it. But as I said, the string is arriving as null each time. Any ideas?
Thanks very much.
UPDATE: It was answered that my problem was that I was not using a key/value pair as a parameter to $.post(). So I tried this, but the string still arrived at the Controller as null:
$.post("/Journal/SaveEntry", { "jsonData": JSONstring });
Answered. I did not have the variable names set correctly after my first Update. I changed the variable name in the Controller to jsonData, so my new Controller header looks like:
public void SaveEntry(string jsonData)
and my post action in JS looks like:
$.post("/Journal/SaveEntry", { jsonData: JSONstring });
JSONstring is a "stringified" (or "serialized") JSON object that I serialized by using the JSON plugin offered at json.org. So:
JSONstring = JSON.stringify(journalEntry); // journalEntry is my JSON object
So the variable names in the $.post, and in the Controller method need to be the same name, or nothing will work. Good to know. Thanks for the answers.
Final Answer:
It seems that the variable names were not lining up in his post as i suggested in a comment after sorting out the data formatting issues (assuming that was also an issue.
Actually, make sure youre using the
right key name that your serverside
code is looking for as well as per
Olek's example - ie. if youre code is
looking for the variable data then you
need to use data as your key. –
prodigitalson 6 hours ago
#prodigitalson, that worked. The
variable names weren't lining up. Will
you post a second answer so I can
accept it? Thanks. – Mega Matt 6 hours
ago
So he needed to use a key/value pair, and make sure he was grabbing the right variable from the request on the server side.
the data argument has to be key value pair
$.post("/Journal/SaveEntry", {"JSONString": JSONstring});
It seems dataType is missed. You may also set contentType just in case. Would you try this version?
$.ajax({
url: '/Journal/SaveEntry',
type: 'POST',
data: JSONstring,
dataType: 'json',
contentType: 'application/json; charset=utf-8'
});
Cheers.
Thanks for answer this solve my nightmare.
My grid
..
.Selectable()
.ClientEvents(events => events.OnRowSelected("onRowSelected"))
.Render();
<script type="text/javascript">
function onRowSelected(e) {
id = e.row.cells[0].innerHTML;
$.post("/<b>MyController</b>/GridSelectionCommand", { "id": id});
}
</script>
my controller
public ActionResult GridSelectionCommand(string id)
{
//Here i do what ever i need to do
}
The Way is here.
If you want specify
dataType: 'json'
Then use,
$('#ddlIssueType').change(function () {
var dataResponse = { itemTypeId: $('#ddlItemType').val(), transactionType: this.value };
$.ajax({
type: 'POST',
url: '#Url.Action("StoreLocationList", "../InventoryDailyTransaction")',
data: { 'itemTypeId': $('#ddlItemType').val(), 'transactionType': this.value },
dataType: 'json',
cache: false,
success: function (data) {
$('#ddlStoreLocation').get(0).options.length = 0;
$('#ddlStoreLocation').get(0).options[0] = new Option('--Select--', '');
$.map(data, function (item) {
$('#ddlStoreLocation').get(0).options[$('#ddlStoreLocation').get(0).options.length] = new Option(item.Display, item.Value);
});
},
error: function () {
alert("Connection Failed. Please Try Again");
}
});
If you do not specify
dataType: 'json'
Then use
$('#ddlItemType').change(function () {
$.ajax({
type: 'POST',
url: '#Url.Action("IssueTypeList", "SalesDept")',
data: { itemTypeId: this.value },
cache: false,
success: function (data) {
$('#ddlIssueType').get(0).options.length = 0;
$('#ddlIssueType').get(0).options[0] = new Option('--Select--', '');
$.map(data, function (item) {
$('#ddlIssueType').get(0).options[$('#ddlIssueType').get(0).options.length] = new Option(item.Display, item.Value);
});
},
error: function () {
alert("Connection Failed. Please Try Again");
}
});
If you want specify
dataType: 'json' and contentType: 'application/json; charset=utf-8'
Then Use
$.ajax({
type: 'POST',
url: '#Url.Action("LoadAvailableSerialForItem", "../InventoryDailyTransaction")',
data: "{'itemCode':'" + itemCode + "','storeLocation':'" + storeLocation + "'}",
contentType: "application/json; charset=utf-8",
dataType: 'json',
cache: false,
success: function (data) {
$('#ddlAvailAbleItemSerials').get(0).options.length = 0;
$('#ddlAvailAbleItemSerials').get(0).options[0] = new Option('--Select--', '');
$.map(data, function (item) {
$('#ddlAvailAbleItemSerials').get(0).options[$('#ddlAvailAbleItemSerials').get(0).options.length] = new Option(item.Display, item.Value);
});
},
error: function () {
alert("Connection Failed. Please Try Again.");
}
});
If you still can't get it to work, try checking the page URL you are calling the $.post from.
In my case I was calling this method from localhost:61965/Example and my code was:
$.post('Api/Example/New', { jsonData: jsonData });
Firefox sent this request to localhost:61965/Example/Api/Example/New, which is why my request didn't work.

Resources