Updating a model w/ Backbone.js + Rails not working (PUT route not found)
In backbone.js I'm updating a category model:
@category.save {
name : category_name,
}
This saves fine and updates the collection properly in backbone. But on the rails serverside its not saving because of a routing error:
Started PUT "/categories" for 127.0.0.1 at 2011-05-24 11:18:16 -0400
ActionController::RoutingError (No route matches "/categories"):
The problem is that rails expects PUT/update to have a url including the id "/categories/:id", not just "/categories"
I tested this out by changing the model url from:
class Category extends Backbone.Model
name: 'category'
url: ->
host + '/categories'
to
class Category extends Backbone.Model
name: 'category'
url: ->
host + '/categories/2'
This works fine.
Started PUT "/categories/2" for 127.0.0.1 at 2011-05-24 11:44:08 -0400
Processing by CategoriesController#update as JSON
Parameters: {"category"=>{"created_at"=>2010-03-14 16:30:07 -0400, "id"=>2, "name"=>"Lunchr5", "updated_at"=>2010-03-14 16:30:07 -0400, "user_id"=>1}, "api_key"=>"s1boakDIav30V6DzOFsY", "id"=>"2"}
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`single_access_token` = 's1boakDIav30V6DzOFsY' LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
SQL (0.1ms) BEGIN
AREL (0.3ms) UPDATE `users` SET `visit_count` = 11, `perishable_token` = 'YG3s4yB01FxUMdMcK8m', `updated_at` = '2011-05-24 15:44:08' WHERE `users`.`id` = 1
开发者_JS百科 SQL (0.3ms) COMMIT
Option Load (0.3ms) SELECT `options`.* FROM `options` WHERE (`options`.user_id = 1) LIMIT 1
Category Load (0.2ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 2 LIMIT 1
SQL (0.1ms) BEGIN
Category Load (13.1ms) SELECT `categories`.`id` FROM `categories` WHERE `categories`.`user_id` = 1 AND (`categories`.`name` = BINARY 'Lunchr5') AND (`categories`.id <> 2) LIMIT 1
AREL (0.3ms) UPDATE `categories` SET `name` = 'Lunchr5', `updated_at` = '2011-05-24 15:44:09' WHERE `categories`.`id` = 2
SQL (0.3ms) COMMIT
Redirected to http://localhost:3000/categories
Completed 302 Found in 179ms
Do I have to hack backbone to add the :id to the url or am I missing something?
Backbone will determine the url to use from the result of Model.url(). So if you have
class Category extends Backbone.Model
name: 'category'
url: ->
host + '/categories'
The url backbone's save method will try on the server will be: host+'/categories'
If you do not define a url function, the default behaviour for the url function will delegate to the collection that it is in. So if you have a collection
class Categories extends Backbone.Collection
model:Category
url: ->
host + '/categories'
class Category extends Backbone.Model
name: 'category'
and instance of Category that belongs to a Categories collection will automatically get use the url host+'/categories'+'/'+category.id to save to the server.
Now if your model is not part of a collection, then you can't do this. You have to override the url function in your model so something like this
class Category extends Backbone.Model
name: 'category'
url: ->
u = "#{host}/categories/"
u = "#{u}#{this.id}" if this.id
u
Note that this is not hacking. This is using backbone correctly. In fact in future editions of backbone, I believe there will be no default behaviour of the url function, and the url function will have to be written for all Models.
When using a model outside of a collection, provide a url root:
class Category extends Backbone.Model
urlRoot: '/categories'
http://backbonejs.org/#Model-urlRoot
If your category is present on the server side, then you category object should have an ID and everything just work. From the code you sent, the id was not set:
@category.save {
name : category_name
}
add the ID when instantiating the category and it should be ok otherwise backbone will try to create the category on the backend with a POST. If you specify the ID it will do a PUT. That is if you setup a collection for your object.
http://documentcloud.github.com/backbone/#Sync
精彩评论