My work: Rails4 + Ember.js(1.0.0).
Problem:
When i linkTo '#/posts/1' from '#/posts', it's ok.
But then, if i refresh(F5) in '#/posts/1' route, browser will load '#/posts' route and not '#/posts/1' which is i want.
Why? Any reasons?
In router.js.coffee:
App.Router.map ()->
#resource 'posts', ()->
#route 'new'
#route 'edit', {path: '/:post_id'}
routes:
App.PostsEditRoute = Ember.Route.extend({
model: (params)->
return App.Post.find(params.post_id)
})
controller:
App.PostsEditController = Ember.ObjectController.extend({
actions: {
update: ()->
// $('button[name=update]').find('.btn-load').addClass('active')
#get('content.transaction').commit()
}
})
Thanks and HappyNewYear,
Updated
#kingpin2k
DAtrs.Store = DS.Store.extend
revision: 13,
adapter: 'DS.RESTAdapter'
, and
gem 'ember-rails'
gem 'ember-source', '1.0.0'
gem 'handlebars_assets', '~> 0.14.1'
gem 'emblem-rails'
#steve-h
Yes! In theory u're right.
I changed 'edit' to 'post'
I tested with console.log in PostIndexRoute.
it was not called in before, but ur answer #resource.
Thanks!
However, the refresh problem is still existed.
And, it generated a new problem. when i linkTo the route /posts/:post_id, it does not show information, but before.(ur answer explained it)
Because and then, i saw console in browswer. it took a request of '/posts.json', not '/posts/1.json'. Why?
what's your understanding of ember-data and DS.RESTAdapter.
routes:
App.PostIndexRoute = Ember.Route.extend({
model: (params)->
console.log '...PostIndexRoute......'
return App.Post.find(params.post_id)
})
i confirmed '/posts/1.json' and it worked :
{
"post": {
"title": "Hello World",
"id": 1
}
}
Sorry and Thanks!
Updated-2
Because and then, i saw console in browswer. it took a request of '/posts.json', not '/posts/1.json'. Why?
Means:
when i linkTo the route /posts/:post_id, it does not show information.
but in console:
...PostIndexRoute......
XHR finished loading: "/posts".
i don't know why it does not "/posts/1"?
and when i refresh browser this time, it will redirect to '/#/posts'.
Your router setup seems to be the problem. try:
App.Router.map ()->
#resource 'posts', ()->
#route 'new'
#resource 'edit', {path: '/:post_id'}
When you {{link-to}}, you are passing the model object directly and the model: function on the route is not called. When you refresh, you are reconstructing the model given the id. Specifying resource for the edit path will make Ember use your PostsEditRoute.
Related
I have a NodeJS backend call with MongoDB. This particular api call was working fine for a long time, and when testing out something on the frontend, I realized the call was not going through. I've checked the routes, controller, index files, and tested the call through Postman which works fine, no errors, and even returns an ObjectId (which means it must be interacting with the database, right?). However, when I search the mongo shell nothing comes back, which tells me it is not saving. I cannot find anything wrong and get no errors anywhere along the way. I checked on MongoDB Atlas, the collection only has 4kb of data so it is not that it is 'too full' and have tested all the other api calls (get, patch, delete) which work fine and have no issues like this in my other collections.
Even weirder, during the save call I push the ID to 2 other collection's documents as a ref. The Mongo shell does show that the new Id is populating to the other documents, but yet it is not saving the actual document... which should be happening prior to the push and needs to happen in order to get the ObjectId
Below is the controller for adding a new Visit document, the route for it, and the response from postman. I really have no idea of how else to determine what is taking place.
Controller
exports.addVisit = async (req, res) => {
const hoursValue = getTotalHours(req.body.visitStart, req.body.visitEnd)
try {
const visit = new Visit({
totalHours: hoursValue,
user: req.body.user,
client: req.body.client,
visitStart: req.body.visitStart,
visitEnd: req.body.visitEnd,
location: req.body.location
});
const user = await User.findById(req.body.user);
const client = await Client.findById(req.body.client);
visit.user = user._id
visit.client = client._id
visit.save();
user.visits.push(visit._id);
user.save();
client.visits.push(visit._id);
client.save();
console.log(visit)
console.log(user)
console.log(client)
res.status(201).send(visit);
} catch (error) {
res.status(400)
res.send({ error: "Error adding visit", error})
}
}
Route
router.route("/visits").post(addVisit)
Postman call to: http://localhost:5000/visitapi/visits
{
"client": "6205a8313fe12d6b4ec354c4",
"location": "Home",
"user": "62410a1dcaac9a3d0528de7a",
"visitStart": "2022-10-12T17:00:00.000Z",
"visitEnd": "2022-10-12T19:00:11.000Z"
}
Postman response
{
"client": "6205a8313fe12d6b4ec354c4",
"user": "62410a1dcaac9a3d0528de7a",
"location": "Home",
"visitStart": "2022-10-12T17:00:00.000Z",
"visitEnd": "2022-10-12T19:00:11.000Z",
"totalHours": 2,
"goals": [],
"id": "635302bb48e85ff6ad17ee59"
}
NodeJs console logging the same new document with no errors:
{
client: new ObjectId("6205a8313fe12d6b4ec354c4"),
user: new ObjectId("62410a1dcaac9a3d0528de7a"),
location: 'Home',
visitStart: 2022-10-12T17:00:00.000Z,
visitEnd: 2022-10-12T19:00:11.000Z,
totalHours: 2,
_id: new ObjectId("635302bb48e85ff6ad17ee59"),
goals: []
}
MongoShell showing the Client collection document stored the new Visit document Id:
visits: [
ObjectId("6257158d157e807e51c7e009"),
ObjectId("62fd852a252b83f4bc8f9782"),
ObjectId("63056cee252b83f4bc8f97e9"),
ObjectId("634ee01ec582da494032c73e"),
ObjectId("634ee09cc582da494032c7aa"),
ObjectId("634ee3d6ddbe3f7e6641d69e"),
ObjectId("634efcf1ddbe3f7e6641d6f9"),
ObjectId("634efdd3ddbe3f7e6641d71b"),
ObjectId("635029937da8972360d907c1"),
ObjectId("6350a0e37da8972360d9084f"),
ObjectId("635302bb48e85ff6ad17ee59") //_id matches the same returned by Postman/ NodeJS
],
Again, everything goes through with no errors on postman or the front or back end, and the backend even logs the returns the new document but no new document is being saved to the DB unless I manually pass it in the Mongosh shell, and only for this one collection. Totally lost, I'd appreciate any guidance on how to explore/ resolve this. Thanks
Edited to include the solution based on the discussion in comment
The problem could be in the mongoose schema. If the property names do not match, mongoose will simply ignore the mismatched properties.
Previous answer
Those mongodb calls are expected to be async. You might want to add await to all those.
visit.user = user._id
visit.client = client._id
await visit.save(); // <- this
user.visits.push(visit._id);
await user.save(); // <- this
client.visits.push(visit._id);
await client.save(); // <- and this
I've been tearing my hair out over this for ages now - and I hope someone can help me :)
I've been trying to stub a network request in Cypress for ages now.
commands.js
Cypress.Commands.add('login', (
email = 'email',
password = 'pass'
) => {
cy.server();
cy.visit('url');
cy.get('input[name="username"').type(email);
cy.get('form').submit();
cy.get('input[name="password"').type(password);
cy.get('form').submit();
});
mock.js
describe('mock', function() {
it('user can login', function() {
cy.login();
cy.get('main[role="main"]');
cy.route('GET',
'**/getIncentives*',
{info: {}, results: {}}
).as('oppty');
cy.wait('#oppty');
});
});
Chrome dev tools request
Cypress request failed
Any help here would be really appreciated - I've been going crazy!
Thanks so much,
Ollie
Currently, Cypress cy.route can only stub network requests that use XHRs
Native HTML form elements don't use XMLHTTPRequest, hence you cannot use cy.route to stub it.
Most people don't run into this issue because using native HTML forms is not as common nowadays
Edit:
You are also waiting on the route, but haven't actually done anything in your test. Your test should look something like this:
cy.route('GET',
'**/getIncentives*',
{info: {}, results: {}}
).as('oppty');
// cypress code that would cause a network request.
cy.wait('#oppty');
Also, make sure the request is of type:XHR:
Cypress will only find the network request after it's been aliased. The code in your question indicated you're not doing an action that would cause a network request:
cy.route('GET',
'**/getIncentives*',
{info: {}, results: {}}
).as('oppty');
// cypress expected something to cause a network request here
cy.wait('#oppty');
You should either move the call to route earlier in the test, or move the code that causes the request after the call to route.
Also note that cy.route() may not work with server side rendering (apparently).
I've had this problem when using NextJs, and solved it by first calling some other page, then navigate on the client to the page I actually want to test.
Like so:
describe('test cy.route', function() {
it( 'test 1', () => {
cy.server();
cy.route({
method: 'GET',
url: /.*\/api\/someApiCall/,
response: { 'someApiResponse': 'ok' },
status: 200
} ).as('myRouteAlias');
// go to start page: first page is server side rendered. cy.route doesn't work.
cy.visit('/');
// go to page to be tested: client side, cy.route works then.
cy.get( `a[href="/pageToBeTested"` ).should('exist').click();
// wait for page loaded
cy.url().should('include', 'pageToBeTested' );
// do something that requests '/api/someApiCall'.
invokeFunctionThatDoesTheRequest();
// wait for the request
cy.wait('#myRouteAlias');
});
});
Restangular has been throwing me a 404 when sending PUT requests, and I'm not sure why.
I have an Events collection, and I'm getting a single event and updating it in a form.
According to the Restangular docs, when I make a PUT request on the Event, it should route to api/events/:eventId. Instead, I'm getting an error saying it's routing to api/events.
The error:
PUT http://localhost:9000/api/events 404 (Not Found)
Can you see where I'm going wrong? I haven't changed the config on Restangular at all.
Here's my controller:
var restEvent = Restangular.one("api/events", $routeParams.eventId);
restEvent.get().then(function(eventData) {
// the eventData is successfully coming through
$scope.thisEvent = Restangular.copy(eventData);
// $scope.thisEvent is modified in the form
// updateEvent() runs when my Event form is submitted
$scope.updateEvent = function() {
$scope.thisEvent.put();
};
});
Here's my Express update routes:
// update route -------------
app.route('/api/events/:event_id')
.get(events.show)
.put(events.updateEvent);
Any suggestions?
This is actually an issue with Restangular/Mongo. Restangular defaults its primary key to "id", whereas Mongo uses "_id". When Restangular tries to append "id" from the Event object to api/events, it can't find "id" and only routes to api/events.
Here's the code that the Restangular docs suggest, and that solves this issue:
app.config(function(RestangularProvider) {
RestangularProvider.setRestangularFields({
id: "_id"
});
});
It could be browser problem, I would recommend to go for this for PUT and PATCH:
app.config(function(RestangularProvider) {
RestangularProvider.setMethodOverriders(['put', 'patch']);
});
I have the following (simplified for example) angular directive which creates a dropzone
directives.directive('dropzone', ['dropZoneFactory', function(dropZoneFactory){
'use strict';
return {
restrict: 'C',
link : function(scope, element, attrs){
new Dropzone('#'+attrs.id, {url: attrs.url});
var myDropZone = Dropzone.forElement('#'+attrs.id);
myDropZone.on('sending', function(file, xhr, formData){
//this gets triggered
console.log('sending');
formData.userName='bob';
});
}
}
}]);
As you can see the the sending event handler I'm trying to send the username ("bob") along with the uploaded file. However, I can't seem to retrieve it in my route middleware as req.params comes back as an empty array (I've also tried req.body).
My node route
{
path: '/uploads',
httpMethod: 'POST',
middleware: [express.bodyParser({ keepExtensions: true, uploadDir: 'uploads'}),function(request,response){
// comes back as []
console.log(request.params);
//this sees the files fine
console.log(request.files);
response.end("upload complete");
}]
}
Here is what the docs say on the sending event
Called just before each file is sent. Gets the xhr object and the formData objects as second and third parameters, so you can modify them (for example to add a CSRF token) or add additional data.
EDIT
I dropped the programmatic approach for now. I have two forms submitting to the same endpoint, a regular one with just post and a dropzone one. Both work, so I don't think it's an issue with the endpoint rather with how I handle the 'sending' event.
//Receives the POST var just fine
form(action="http://127.0.0.1:3000/uploads", method="post", id="mydz")
input(type="hidden", name="additionaldata", value="1")
input(type="submit")
//With this one I can get the POST var
form(action="http://127.0.0.1:3000/uploads", method="post", id="mydz2", class="dropzone")
input(type="hidden", name="additionaldata", value="1")
OK, I've actually figured it out, thanks to Using Dropzone.js to upload after new user creation, send headers
The sending event:
myDropZone.on('sending', function(file, xhr, formData){
formData.append('userName', 'bob');
});
As opposed to formData.userName = 'bob' which doesn't work for some reason.
I would like to add to NicolasMoise's answer.
As a beginner in webdev I got stuck on how to obtain an instance of Dropzone. I wanted to retrieve an instance of Dropzone that had been generated by the autodiscovery feature. But it turns out that the easiest way to do this is to manually add a Dropzone instance after first telling Dropzone not to auto-discover.
<input id="pathInput"/>
<div id="uploadForm" class="dropzone"/>
<script>
$(document).ready(function(){
Dropzone.autoDiscover = false;
var dZone = new Dropzone("div#uploadForm", {url: "/api/uploads"});
dZone.on("sending", function(file, xhr, data){
data.append("uploadFolder", $("#pathInput")[0].value);
});
});
</script>
Serverside the data will be in request.body.uploadFolder
Nicolas answer is one possible solution to the problem. It is especially useful if you need to alter the file object prior to sending.
An alternative is to use the params option:
var myDropzone = new Dropzone("div#myId",
{ url: "/file/post", params: { 'param_1': 1 }});
cf. the documention
For those that are using thatisuday/ng-dropzone the callback methods are done as such:
<ng-dropzone class="dropzone" options="dzOptions" callbacks="dzCallbacks" methods="dzMethods"></ng-dropzone>
In a controller:
$scope.dzCallbacks = {
sending: function(file, xhr, form) {
console.log('custom sending', arguments);
form.append('a', 'b');
}
};
I am updating a form and i want to make an update request on the serverwith an id
my model is:
var CampaignEditModel = Backbone.Model.extend({
urlRoot:"http://localhost:3033/campaign/update/",
url : function(){
var url = this.urlRoot + this.id;
return url;
},
idAttribute: "_id",
defaults:{
"id":null ,
"Name" :""
}
});
render function is called here:
$contents.empty().append(new EditView({model:editCampaigns}).render({id:id}).el);
and render function is:
render: function(options){
this.$el.append( _.template(EditTemplate));
this.model.set({"id":options.id})
console.log(this.model.get("id"));
this._modelBinder.bind(this.model, this.el);
return this;
},
events: {
'click .saveCampaign ': 'save'
},
save:function(){
this.model.set({
"Name" :$('#edname').val(),
});
this.model.save(null, {success: function(data){
console.log("data:" + data);
require(['campaignroute'],function(routes){
var router = routes.pageRouter;
router.navigate('gridView', {trigger: true});
});
}});
return false;
}
the problem is even i have set an id in the model still when save method is called
the request go like this
http://localhost:3033/campaign/update/undefined
and console shows the eror:
Failed to load resource: the server responded with a status of 404 (Not Found)
how to solve this problem?
Instead of passing options to your custom render(options) function and setting the model id there, set the it directly on the editCampaigns model, before entering render(options):
editCampaigns.set('id', id);
$contents.empty().append(new EditView({model:editCampaigns}).render().el);
and remove the extra
this.model.set({"id":options.id})
from render(options) together with the options parameter. It should look like similar to this:
render: function(){
this.$el.append( _.template(EditTemplate));
console.log(this.model.get("id"));
this._modelBinder.bind(this.model, this.el);
return this;
}
Your model also has an extra url function:
url : function(){
var url = this.urlRoot + this.id;
return url;
}
you don't need this one since the models' id is automatically appended after urlRoot.
Unrelated to you problem I see you used
http://localhost:3033/campaign/update
to define your update URL. The HTTP method you use, already says what kind of action will be executed, this is the reason why you can (and should) write URLs without verbs. Just remove the extra /update.
Here is a quick summary about best-practices:
How to create REST URLs without verbs?
Double check that the request is a post request and not a put request. 'Failed to load resource' errors is usually related to a missing request handler.