Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
  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?

like image 383
kush Avatar asked May 24 '11 15:05

kush


2 Answers

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.

like image 75
34m0 Avatar answered Oct 05 '22 03:10

34m0


When using a model outside of a collection, provide a url root:

class Category extends Backbone.Model
  urlRoot: '/categories'

http://backbonejs.org/#Model-urlRoot

like image 44
Leo Romanovsky Avatar answered Oct 05 '22 05:10

Leo Romanovsky