AngularJS: Retrieve newly created Record Id in CoffeeScript - ruby-on-rails

To create a new record added from a form in AngularJS, I have:
task = Task.save($scope.newTask)
But I need to also retrieve the new id that was created upon save. The answer found here: Not getting updated values after call to AngularJS $save seems to address what I need, but when I convert to CoffeeScript:
task = $scope.newTask
task.$save (msg, headers) ->
console.log task.id
It does not work. I am using Ruby on Rails. Any help is appreciated.
Edit:
I am getting the error on the code above: "Object # has no method 'save'"
Here is a bigger picture of my code:
app = angular.module("appName", ["ngResource"])
app.factory "Task", ["$resource", ($resource) ->
$resource("/projects/:project_id/tasks/:id", {project_id: "#project_id", id: "#id"}, {update: {method: "PUT"}, destroy: { method: 'DELETE' }})
]
#TaskCtrl = ["$scope", "Task", ($scope, Task) ->
$scope.tasks = Task.query()
$scope.saveTask = ->
task = $scope.newTask
task.$save (msg, headers) ->
console.log task.id
$scope.tasks.push(task)
$scope.newTask = {}
]

You are trying to save newTask as it was an instance of the Task resource, but it is not, you are creating it as an empty object ($scope.newTask = {}).
You should create it as $scope.newTask = new Task()
Or save is as you seem to suggest in the first line of code: Task.save($scope.newTask).
The result of the Task.save() call will depend on what the server returns, it's JSON data, if you return the new ID in the JSON response of the POST request, then you'll get it in your data, if you just return an empty "created" response, with a Location header, you shuld subsequently retrieve the data. If you return nothing at all, that's the point in which you touch ruby, and return something useful from the server.

Related

cy.url() and/or cy.location('href') does not return a string

I have an editor page. When I add any content and click the "Save" button my URL will change, adding a random id in the URL. I want to check if my ID's are changing every time when I click the "Save button".
I save the URL result in variable and want to check it, I do it like this:
const currentURL = cy.url();
cy.get('.editor-toolbar-actions-save').click();
cy.url().should('not.eq', currentURL);
But my currentURL variable's type is not string:
expected http://localhost:8080/editor/37b44d4d-48b7-4d19-b3de-56b38fc9f951 to not equal { Object (chainerId, firstCall) }
How I can use my variable?
tl;dr
Cypress commands are asynchronous, you have to use then to work with their yields.
cy.url().then(url => {
cy.get('.editor-toolbar-actions-save').click();
cy.url().should('not.eq', url);
});
Explanation
A similar question was asked on GitHub, and the official document on aliases explains this phenomenon in great detail:
You cannot assign or work with the return values of any Cypress command. Commands are enqueued and run asynchronously.
The solution is shown too:
To access what each Cypress command yields you use .then().
cy.get('button').then(($btn) => {
// $btn is the object that the previous
// command yielded us
})
It is also a good idea to check out the core concepts docs's section on asynchronicity.
These commands return a chainable type, not primitive values like strings, so assigning them to variables will require further action to 'extract' the string.
In order to get the url string, you need to do
cy.url().then(urlString => //do whatever)
I have been having the same issue and so far most consistent method has been to save the URL to file and read it from file when you need to access it again:
//store the url into a file so that we can read it again elsewhere
cy.url().then(url => {
const saveLocation = `cypress/results/data/${Cypress.spec.name}.location.txt`
cy.writeFile(saveLocation, getUrl)
})
//elsewhere read the file and do thing with it
cy.readFile(`cypress/results/data/${Cypress.spec.name}.location.txt`).then((url) => {
cy.log(`returning back to editor ${url}`)
cy.visit(url)
})
Try this:
describe("Test Suite", () => {
let savedUrl;
beforeEach(() => {
cy.visit("https://duckduckgo.com/");
cy.url().then(($url) => {
savedUrl = $url;
});
});
it("Assert that theURL after the search doens't equal the URL before.", () => {
cy.get("#search_form_input_homepage").type("duck");
cy.get("#search_button_homepage").click();
// Check if this URL "https://duckduckgo.com/?q=duck&t=h_&ia=web"
// doesn't equal the saved URL "https://duckduckgo.com/"
cy.url().should("not.eq", savedUrl);
});
});
Refer below code snippet, Here you can get the current URL and store it in a variable, do print via cy.log()
context('Get Current URL', () => {
it('Get current url and print', () => {
cy.visit('https://docs.cypress.io/api/commands/url')
cy.url().then(url => {
const getUrl = url
cy.log('Current URL is : '+getUrl)
})
})
})
#Max thanks this helped to get some ideas on different versions.
The way I did it is:
Create a .json file in your fixtures folder (name it whatever you want).
On the new .json file, only add: { } brackets and leave the rest blank. The function will self populate that .json file.
Create a new function on the commands page to easily call it on your test.
It would probably be best to create two functions, 1 function to write url or the sliced piece of the url, and the another function to call it so you can use it.
A. Example of 1st method, this method cuts the id off of the URL and stores it on the .json file:
Cypress.Commands.add('writeToJSON', (nameOfJSONSlicedSection) =>
{
cy.url().then(urlID =>
{
let urlBit = urlID.slice(urlID.indexOf('s/') + 2, urlID.indexOf('/edit'))
cy.writeFile('cypress/fixtures/XYZ.json', {name: nameOfJSONSlicedSection, id: urlBit}) /*{ }<-- these will populate the json file with name: xxxxx and id:xxxxx, you can changes those to whatever meets your requirements. using .slice() to take a section of the url. I needed the id that is on the url, so I cut only that section out and put it on the json file.*/
})
})
B. 2nd example function of calling it to be used.
This function is to type in the id that is on the url into a search box, to find the item I require on a different it() block.
Cypress.Commands.add('readJSONFile', (storedJSONFile) =>
{
cy.readFile('cypress/fixtures/XYZ.json').its('id').then((urlSetter) => {
cy.log(storedJSONFile, 'returning ID: ' + urlSetter)
//Search for Story
cy.get('Search text box').should('be.visible').type(urlSetter, {delay: 75})
})
})
/*here I use a .then() and hold the "id" with "urlSetter", then I type it in the search box to find it by the id that is in the URL. Also note that using ".its()" you can call any part section you require, example: .its('name') or .its('id') */
I hope this helps!

Posting/receiving JSON object

So I am using this code to post:
$.ajax({
url: '/validator/ValidationController/validate',
data : JSON.stringify(parameters),
contentType : 'application/json',
type : 'POST'
})
And this to receive, both being triggered by the same button press. But it's just getting a null object.
def validate(){
Thread.currentThread().sleep(1000)
def parameters = request.JSON;
assert parameters.a == "a_value";
}
When I hover over the validate function, it's referred to as: Object validator.ValidationController.validate() I'm assuming the url is wrong.
Note: I am pretty inexperienced with this, speaking to me like I'm 5 is encouraged!
We would need more code to see how you are sending and receiving but it seems like you are not handling the asynchronous aspect. In simple terms, you are sending out the request and immediately trying to handle the response, even though it is not back yet and even though you tried to sleep. Check out the complete config for the ajax function. Something like this:
$.ajax({
url: '/validator/ValidationController/validate',
data : JSON.stringify(parameters),
contentType : 'application/json',
type : 'POST',
complete: function(request, success){
validate(request)
}
})
def validate(request){
Thread.currentThread().sleep(1000)
def parameters = request.JSON;
assert parameters.a == "a_value";
}

Custom resource method's URL not respected

I'm trying to make a list of persons. My HTTP server is able to give a JSON representation of a person on URLs like /person/[id].json, and a list of all persons at /person.infinity.json.
So I have the controller, where I have defined the Person resource:
var app = angular.module('myApp', ["ngResource"])
.controller('PersonController', function PersonController($scope, $http, $resource) {
var Person = $resource("/person/:personId.json",
{ personId: '#id' },
{ list: {method: "GET", url: "/person.infinity.json", isArray: true}}
);
$scope.persons = Person.list();
});
However, when Person.list() is called, my custom URL for the list method (/person.infinity.json) is not used. Chrome´s network inspector reveals that a request is fired to /person/.json, that is, the default resource URL with no parameter set.
Obviously, I would like Person.list() to result in a request to /person.infinity.json.
What am I doing wrong?
I was using angular-resource 1.0.7, in which URL override was not implemented. It was implemented in this pull request: https://github.com/angular/angular.js/pull/1890
Switching to version 1.1.5 solved the problem.

Force jQuery.load() to POST when using jQuery.param()

Ok, so .load() uses...
The POST method is used if data is
provided as an object; otherwise, GET
is assumed.
I have the following...
// an array of itemIds
var items = $selected.map(function() {
return $(this).find('.item').text();
}).get();
// post the data
$container.load(
_url,
$.param(data, true),
function(response, status, xhr) {
//...
}
);
The problem I have is that if I use $.param to serialise the data, it seems that GET is used.
If I don't use $.param then POST is used but I run into the problem again with the array not being serialised correctly and I don't receive the data in my controller.
Is there an easy way around this?
You can use jQuery.get() instead of .load():
$.get(_url, $.param(data, true), function(data) {
$container.html(data);
});
This will have the same effect as a call to load with parameters, but with a GET request instead of a POST request.

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