开发者

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜