开发者

Backbone.js and Rails - How to handle params from Backbone models?

In a standard Rails controller, I'd create a record like this:

@user = User.new(params[:user])

This assumes that the form parameters that come in are nested.

I've been playing with Backbone.js and I noticed that by default, Backbone doesn't nest the parameters the way a normal Rails form might, which is actually somet开发者_如何学Pythonhing I expected. So I'm wondering what I should do...

Do I

figure out on the server-side if it's a request from Backbone by looking at accepts headers, etc and manipulate the params myself so I can keep my controller code small:

do_some_params_manipulation_with(params)
@user = User.new(params[:user])
respond_to do |format|
  if @user.save
    format.html {redirect_to users_url}
    format.json {render :json => @user.to_json }
  end
end

Or, do I instantiate the object in each branch which ends up with repeated code but might be more maintainable in the long run....

respond_to do |format|
  format.html do
    @user = User.new(params[:user])
    if @user.save
      redirect_to users_url
    end
  end

  format.json do
    @user = User.new(params) # and rely on mass-assignment protection
    if @user.save
      render :json => @user.to_json
    end
  end

end

or do I modify my Backbone.js models by overriding the .toJSON method (which I'm not entirely sure how to do because I don't know enough about Backbone.js yet) so that it nests the params?

In this situation, I have access to both sides of the app, but I am interested in what others are doing.


It's nice when you can have the general Rails forms and Backbone forms match with respect to the root node. That's why in my last application I chose to override the Backbone models' toJSON method.

You could override the global toJSON method as Raimonds Simanovskis suggested. But even the non-DRY way approach isn't so bad. Just one line of boilerplate for each model definition:

// Depends on Underscore.js
User = Backbone.Model.extend({
  toJSON: function() {
    return { user: _.clone( this.attributes ) }
  },
  // Your other methods here
});

Edit: Corrected code sample. Sorry for the errors, I was translating from CoffeeScript to JavaScript.


If you are using the backbone-rails gem, looks like you can do

var User = Backbone.Model.extend({
   paramRoot: 'user'
});

Around line 45 on github

Credit PL J and stream 7 on this link


I have made a little hack to namespace save requests under model.name property. It monkey patches toJSON() during sync() call only and restores original method so you can use it as usual.

I have implemented it in CoffeeScript.

Check it here


It should be noted that if you opt for the currently accepted answer (patching toJSON at the model level) you are affecting reading as well. Maybe that goes without saying, maybe not. But you will have a lot of work to do when rendering models/collections if you put this patch into affect in a backbone app. Therefore, I personally wouldn't use it as-is.


In one of the answers to Rails mass assignment and Backbone.js there is mentioned patch https://gist.github.com/719080 which I think will do what you need.


As of Rails 3.1 there's now a new initializer called wrap_parameters.rb which handles this problem by default. The code that handle this case is:

# Disable root element in JSON by default.
ActiveSupport.on_load(:active_record) do
  self.include_root_in_json = false
end

Bada bing!

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜