I'm fairly new to Backbone so this is probably an obvious mistake...
I've created a customisable form with a few views. I'm pulling in my config data from config.json through my form collection. In the console I'm getting an error:
'POST http://local.ti-url-builder/js/config.json 405 (Method Not Allowed)'
Any ideas? I'm not doing any POST's (that I'm aware of?). I have a feeling its' related to the way I'm pulling the data:
TAG.FormCollection = Backbone.Collection.extend({
model: TAG.FormsModel,
url: "js/config.json",
});
You can view the app here: https://di-campaign.s3.amazonaws.com/redirect/urlbuilder_v2.html
Thanks in advance for any help and useful criticism :)
I visited the link you shared and saw multiple failed POST requests with HTTP status code 412.
Those are getting triggered in form-view.js:
TAG.Section = new TAG.FormSectionCollection();
...
TAG.Section.create( pageAttributes );
The create method of Collection triggers POST request. It saves the model to the server and adds to the collection.
Are you saving a model instance? By default, if you save a model and it doesn't have an id value, a POST request will be sent to the url...
Related
I'm currently building a small demo app using Ember.JS and NodeJS with Express. I've knocked up a simple model and have created an action to save it.
The component has a property called recipe, which is an instance of a model I've defined. The save action is as simple as:
save() {
this.get('recipe').save();
}
Looking at my network tab in Chrome dev tools, I can see the data in the request payload. However, I can't access the data in my Node app. I've logged the full req object and my data isn't there anywhere.
I have a feeling this is to do with the fact that Ember uses the PATCH verb, whereas I'd expect it to use PUT or POST.
Any help is greatly appreciated.
Disclaimer: Without seeing the code it is difficult to give you a definitive answer.
The JSON API specification defines, that updating a resource is done with the PATCH verb. (http://jsonapi.org/format/#crud-updating)
If you chose to use this adapter, you will have to define the appropriate routes in your Express app. Without seeing it, I'd suggest to define the route for PUT and PATCH with the same callback and you'll be fine.
For example:
router.put('/:id', controller.update);
router.patch('/:id', controller.update);
Overriding the HTTP verb in the adapter is not that easy at the moment (Ember Data 2.4). A possible head would be to override the updateRecord method of the adapter. (https://github.com/emberjs/data/blob/v2.4.0/addon/adapters/json-api.js#L115-L133)
Disclaimer: Without seeing the code it is difficult to give you a definitive answer.
You're not receiving the request payload because the 'Content-Type' header has not been set properly.
The JSONAPIAdapter for Ember sends requests with the 'Content-Type' header set to 'application/vnd.api+json'. You'll need to set this in body-parser like so:
app.use(bodyParser.json({ type: 'application/vnd.api+json' }));
In the end, I fixed the issue by using DS.RESTAdapter as opposed to DS.JSONAPIAdapter. The RESTAdapter uses PUT when you save a record while JSONAPIAdapter uses PATCH. I suspect there's some issue in the implementation of PATCH in either Ember or Express.
I'm using v0.10.
Simple blueprint request for a messaging app (my model is named message)
var socket = io.connect('http://localhost:1337');
//initiate the request
socket.request('/message', {}, function(users) {});
socket.on('message', function(m){
console.log(m)
});
Using postman to to delete a message sends the delete to the client, however create does not send anything. Thank you.
UPDATE:
created this repo to reproduce the issues: https://github.com/jamescharlesworth/testProject
Take a look to http://beta.sailsjs.org/#/documentation/reference/Upgrading search that page for "socket" and there you'll find the differences on sails 0.10.
The most important one now is that instead of the "type of message", the first parameter of the "on" is the model. As it was previously used to call "message" to one of the types of messages, perhaps there is a remaining bug or something that filters your "message" model notifications when creating.
Have you tried naming your model different? Just to validate that the issue is with your model's name.
Additionally: if you want some transparent binding of models into an angular app, you can do it seamlessly with angular-sails-bind:
https://github.com/diegopamio/angular-sails-bind
I made it for my own project and then decided to put it as a separated library so everybody could benefit and I could have my first experience developing a bower package.
I hope it could help you.
In your example, you are using autosubscribe: ['destroy', 'create', 'update'],
while in sails 0.10 they have with "ed":
The events that were formerly create, update, and destroy are now created, updated, and destroyed.
That may be your issue.
Working on an app that has real time messages with socket.io, I also need to save the messages. I choose to use mongodb and on the client side I am using backbone.
My problem is when I emit a new message all the sockets/users get the message in real time, but the socket/user that sent the message gets it twice, once from the socket and once from the collection re-rendering.
Here is what my collection view looks like.
module.exports = CollectionView = Marionette.CollectionView.extend({
className: 'collection',
initialize: function() {
//this.listenTo(this.collection, 'change', this.render);
},
itemView: MessageView
});
I commented out this.listenTo(this.collection, 'change', this.render);. So I am asking this question because maybe marionette by default renders the CollectionView? Maybe someone has an explanation for how I can prevent the socket/user that sends a message from being appended twice?
Edit: Just got an idea, instead of appending the message I could just fetch the collection when a new message is made? I tried it and it works, maybe there is a better way? I'm still thinking, and am open to new ideas!
Edit: This worked pretty well for me. Instead of appending the html, I just make a GET request to all the sockets connected, that way they get the fresh data.
createMessage: function(data) {
window.App.data.messages.fetch({
success: function() {
console.log('success')
}
});
//this.$el.find('.message-content').append('<div class="message"><b>'+data.username+':</b>'+data.message+'</div>');
window.App.core.vent.trigger('app:log', 'Chat View: Received a new message!');
}
Only issue with the above is the sequence is POST, then GET within milliseconds of each other, so the GET request may return data before the POST fully finishes.
So I am trying to figure out how I can set a callback so that when the POST successfully adds to the collection make the GET. I'll share the solution if I come to it.
You're not showing your socket.io client code, but I think your second approach is better. Socket should only send/receive data. I assume you have at least 1 event in your socket for "receiveMessage" and 1 emit for "sendMessage".
I think you could, in your client-side socket:
When receiving a message (or I'm notified that I have a new message), add the message to your collection using Collection.add(message). Marionette will render that message for you.
When sending a message, just add it to your collection, or wait for a callback from the server (see the docs) to be sure it was received correctly before adding to the collection.
Never, never, append something to the view's HTML with jQuery if you're using Marionette view! ;)
For your initial message load, use Collection.fetch() the first time (for example, as soon as your socket is connected) to get all messages that were already on the server. From that point on, add individual messages as they come instead of fetching them all (you'll be saving bandwith).
What I do in a similar application, is send from the socket a "Hello" message upon first connection, that includes the data I need. Then I just do Collection.reset(data) with what was sent from the socket, and you're good to go. Your socket will initialize your collection and will be updating it one message at a time.
Hope it helps!
i can save a model on parse.com writing:
var persona=new Person({username:"filiberto",password:"filiberto"});
persona.save( {
success: function (persona) {
console.log("modello salvato nel db");
console.log(persona.url());
}
});
but if i first fetch a collection,get a specified model and update by save method doesn't work and error is:PUT https://api.parse.com/1/classes/_User/V742NGMTjA 400 (Bad Request)
Models.utenti = new Usercollection();
Models.utenti.fetch({async:false});
var current_user=Models.utenti.get(Parse.User.current().id);
current_user.set_last_activity();
current_user.save();<----PUT https://api.parse.com/1/classes/_User/V742NGMTjA 400 (Bad
Request)
I've tried to update another class on parse.com and works. The class that i can't update is users,maybe a security reason?
I'm unfamiliar with Parse, but according to their API (https://www.parse.com/docs/rest#users), a users request should be a POST not a PUT. Backbone uses PUT to update/sync models, whereas POST is used to create new models. The issue might be that Backbone is assuming that your model has already been saved and using the PUT method to update it.
Parse has a nice tutorial demonstrating the users API with Backbone (https://parse.com/tutorials/todo-app-with-javascript). You might also find this discussion addressing saving vs updating Backbone models helpful (Backbone model.save() is sending PUT instead of POST).
UPDATE: It appears that Parse requires Cross-Origin Resource Sharing (CORS) to modify existing users' data. In practice, this means adding additional information in the request header. See Parse's blog post in the comments below for more info and implementation details.
I am more into front end development and have recently started exploring Backbone.js into my app. I want to persist the model data to the server.
Could you please explain me the various way to save the Model data (using json format). I am using Java on server side. Also I have mainly seen REST being used to save data. As i am more into front end dev, i am not aware of REST and other similar stuff.
It would be great if someone could please explain me the process with some simple example.
Basically Models have a property called attributes which are the various values a certain model may have. Backbone uses JSON objects as a simple way to populate these values using various methods that take JSON objects. Example:
Donuts = Backbone.Model.extend({
defaults: {
flavor: 'Boston Cream', // Some string
price: '0.50' // Dollars
}
});
To populate the model there are a few ways to do so. For example, you can set up your model instance by passing in a JSON OR use method called set() which takes a JSON object of attributes.
myDonut = new Donut({'flavor':'lemon', 'price':'0.75'});
mySecondHelping = new Donut();
mySecondHelping.set({'flavor':'plain', 'price':'0.25'});
console.log(myDonut.toJSON());
// {'flavor':'lemon', 'price':'0.75'}
console.log(mySecondHelping.toJSON());
// {'flavor':'plain', 'price':'0.25'}
So this brings us up to saving models and persisting them either to a server. There is a whole slew of details regarding "What is REST/RESTful?" And it is kind of difficult to explain all this in a short blurb here. Specifically with regard to REST and Backbone saving, the thing to wrap your head around is the semantics of HTTP requests and what you are doing with your data.
You're probably used to two kinds of HTTP requests. GET and POST. In a RESTful environment, these verbs have special meaning for specific uses that Backbone assumes. When you want to get a certain resource from the server, (e.g. donut model I saved last time, a blog entry, an computer specification) and that resource exists, you do a GET request. Conversely, when you want to create a new resource you use POST.
Before I got into Backbone, I've never even touched the following two HTTP request methods. PUT and DELETE. These two verbs also have specific meaning to Backbone. When you want to update a resource, (e.g. Change the flavor of lemon donut to limon donut, etc.) you use a PUT request. When you want to delete that model from the server all together, you use a DELETE request.
These basics are very important because with your RESTful app, you probably will have a URI designation that will do the appropriate task based on the kind of request verb you use. For example:
// The URI pattern
http://localhost:8888/donut/:id
// My URI call
http://localhost:8888/donut/17
If I make a GET to that URI, it would get donut model with an ID of 17. The :id depends on how you are saving it server side. This could just be the ID of your donut resource in your database table.
If I make a PUT to that URI with new data, I'd be updating it, saving over it. And if I DELETE to that URI, then it would purge it from my system.
With POST, since you haven't created a resource yet it won't have an established resource ID. Maybe the URI target I want to create resources is simply this:
http://localhost:8888/donut
No ID fragment in the URI. All of these URI designs are up to you and how you think about your resources. But with regard to RESTful design, my understanding is that you want to keep the verbs of your actions to your HTTP request and the resources as nouns which make URIs easy to read and human friendly.
Are you still with me? :-)
So let's get back to thinking about Backbone. Backbone is wonderful because it does a lot of work for you. To save our donut and secondHelping, we simply do this:
myDonut.save();
mySecondHelping.save();
Backbone is smart. If you just created a donut resource, it won't have an ID from the server. It has something called a cID which is what Backbone uses internally but since it doesn't have an official ID it knows that it should create a new resource and it sends a POST request. If you got your model from the server, it will probably have an ID if all was right. In this case, when you save() Backbone assumes you want to update the server and it will send a PUT. To get a specific resource, you'd use the Backbone method .fetch() and it sends a GET request. When you call .destroy() on a model it will send the DELETE.
In the previous examples, I never explicitly told Backbone where the URI is. Let's do that in the next example.
thirdHelping = Backbone.Model.extend({
url: 'donut'
});
thirdHelping.set({id:15}); // Set the id attribute of model to 15
thirdHelping.fetch(); // Backbone assumes this model exists on server as ID 15
Backbone will GET the thirdHelping at http://localhost:8888/donut/15 It will simply add /donut stem to your site root.
If you're STILL with me, good. I think. Unless you're confused. But we'll trudge on anyway. The second part of this is the SERVER side. We've talked about different verbs of HTTP and the semantic meanings behind those verbs. Meanings that you, Backbone, AND your server must share.
Your server needs to understand the difference between a GET, POST, PUT, and DELETE request. As you saw in the examples above, GET, PUT, and DELETE could all point to the same URI http://localhost:8888/donut/07 Unless your server can differentiate between these HTTP requests, it will be very confused as to what to do with that resource.
This is when you start thinking about your RESTful server end code. Some people like Ruby, some people like .net, I like PHP. Particularly I like SLIM PHP micro-framework. SLIM PHP is a micro-framework that has a very elegant and simple tool set for dealing with RESTful activities. You can define routes (URIs) like in the examples above and depending on whether the call is GET, POST, PUT, or DELETE it will execute the right code. There are other solutions similar to SLIM like Recess, Tonic. I believe bigger frameworks like Cake and CodeIgniter also do similar things although I like minimal. Did I say I like Slim? ;-)
This is what excerpt code on the server might look (i.e. specifically regarding the routes.)
$app->get('/donut/:id', function($id) use ($app) {
// get donut model with id of $id from database.
$donut = ...
// Looks something like this maybe:
// $donut = array('id'=>7, 'flavor'=>'chocolate', 'price'=>'1.00')
$response = $app->response();
$response['Content-Type'] = 'application/json';
$response->body(json_encode($donut));
});
Here it's important to note that Backbone expects a JSON object. Always have your server designate the content-type as 'application/json' and encode it in json format if you can. Then when Backbone receives the JSON object it knows how to populate the model that requested it.
With SLIM PHP, the routes operate pretty similarly to the above.
$app->post('/donut', function() use ($app) {
// Code to create new donut
// Returns a full donut resource with ID
});
$app->put('/donut/:id', function($id) use ($app) {
// Code to update donut with id, $id
$response = $app->response();
$response->status(200); // OK!
// But you can send back other status like 400 which can trigger an error callback.
});
$app->delete('/donut/:id', function($id) use ($app) {
// Code to delete donut with id, $id
// Bye bye resource
});
So you've almost made the full round trip! Go get a soda. I like Diet Mountain Dew. Get one for me too.
Once your server processes a request, does something with the database and resource, prepares a response (whether it be a simple http status number or full JSON resource), then the data comes back to Backbone for final processing.
With your save(), fetch(), etc. methods - you can add optional callbacks on success and error. Here is an example of how I set up this particular cake:
Cake = Backbone.Model.extend({
defaults: {
type: 'plain',
nuts: false
},
url: 'cake'
});
myCake = new Cake();
myCake.toJSON() // Shows us that it is a plain cake without nuts
myCake.save({type:'coconut', nuts:true}, {
wait:true,
success:function(model, response) {
console.log('Successfully saved!');
},
error: function(model, error) {
console.log(model.toJSON());
console.log('error.responseText');
}
});
// ASSUME my server is set up to respond with a status(403)
// ASSUME my server responds with string payload saying 'we don't like nuts'
There are a couple different things about this example that. You'll see that for my cake, instead of set() ing the attributes before save, I simply passed in the new attributes to my save call. Backbone is pretty ninja at taking JSON data all over the place and handling it like a champ. So I want to save my cake with coconuts and nuts. (Is that 2 nuts?) Anyway, I passed in two objects to my save. The attributes JSON object AND some options. The first, {wait:true} means don't update my client side model until the server side trip is successful. The success call back will occur when the server successfully returns a response. However, since this example results in an error (a status other than 200 will indicate to Backbone to use the error callback) we get a representation of the model without the changes. It should still be plain and without nuts. We also have access to the error object that the server sent back. We sent back a string but it could be JSON error object with more properties. This is located in the error.responseText attribute. Yeah, 'we don't like nuts.'
Congratulations. You've made your first pretty full round trip from setting up a model, saving it server side, and back. I hope that this answer epic gives you an IDEA of how this all comes together. There are of course, lots of details that I'm cruising past but the basic ideas of Backbone save, RESTful verbs, Server-side actions, Response are here. Keep going through the Backbone documentation (which is super easy to read compared to other docs) but just keep in mind that this takes time to wrap your head around. The more you keep at it the more fluent you'll be. I learn something new with Backbone every day and it gets really fun as you start making leaps and see your fluency in this framework growing. :-)
EDIT: Resources that may be useful:
Other Similar Answers on SO:
How to generate model IDs with Backbone
On REST:
http://rest.elkstein.org/
http://www.infoq.com/articles/rest-introduction
http://www.recessframework.org/page/towards-restful-php-5-basic-tips