moose56
moose56

Reputation: 119

Error when saving a Backbone.js model with Rails

I have Backbone.js collection and model for a project object:

window.Project = Backbone.Model.extend();

window.Projects = Backbone.Collection.extend({
    model: Project, 
    url: '/projects'
});

I have setup a rails controller to respond to the Backbone.js collection:

class ProjectsController < ApplicationController

    def index
        render :json => Project.all
    end

    def create
        project = Project.create! params
        render :json => project
    end

end

Index works fine and I get a list of projects in my web app. The problem is if I try and create a model on the Projects collection I get a 500 error from the server.

The error message on the server is as follows:

Started POST "/projects" for 127.0.0.1 at 2011-08-21 08:27:56 +0100
  Processing by ProjectsController#create as JSON
  Parameters: {"title"=>"another test"}
Completed 500 Internal Server Error in 16ms

ActiveRecord::UnknownAttributeError (unknown attribute: action):
  app/controllers/projects_controller.rb:8:in `create'

I am not sure what the unknown attribute: action is referring to.

For info I have set up the projects_controller as resources :projects. I have also set rails to ActiveRecord::Base.include_root_in_json = false.

Upvotes: 4

Views: 1600

Answers (2)

Matteo Melani
Matteo Melani

Reputation: 2726

You can enable parameter wrapping. Add a file in the initializer directory with:

ActiveSupport.on_load(:action_controller) do
  wrap_parameters format: [:json]
end

and, for json request, you post params will now be wrapped with the model name.

Upvotes: 0

mu is too short
mu is too short

Reputation: 434596

Yes, Rails always adds the action and controller to params. The parameters come from ActionDispatch::Http::Parameters:

def parameters
  @env["action_dispatch.request.parameters"] ||= begin
    params = request_parameters.merge(query_parameters)
    params.merge!(path_parameters)
    encode_params(params).with_indifferent_access
  end
end

And path_parameters:

Returns a hash with the parameters used to form the path of the request. Returned hash keys are strings:

{'action' => 'my_action', 'controller' => 'my_controller'}

So you shouldn't be doing project = Project.create! params. You could go the update_attributes route:

project = Project.new
project.update_attributes params[:model_name]

But this assumes that you have what you need in a sub-hash of params and it won't call your validators. Backbone won't namespace your attributes by default but you could override Backbone.sync and do it yourself. Still, you probably want your validations so update_attributes should generally be avoided.

Your best bet is to pull exactly the attributes out of params that you're expecting to be there. This is even the Backbone recommended practise:

*(In real code, never use update_attributes blindly, and always whitelist the attributes you allow to be changed.)*

Upvotes: 5

Related Questions