Ruby on rails js如何向Rails服务器添加记录?

Ruby on rails js如何向Rails服务器添加记录?,ruby-on-rails,canjs,Ruby On Rails,Canjs,我正在使用Can.js向Ruby on Rails服务器添加记录: var Todo = can.Model({ findAll : 'GET /todos', findOne : 'GET /todos/{id}', create : 'POST /todos', update : 'PUT /todos/{id}', destroy : 'DELETE /todos/{id}' }, {}); Todo.prototype.description = functio

我正在使用Can.js向Ruby on Rails服务器添加记录:

var Todo = can.Model({
  findAll : 'GET /todos',
  findOne : 'GET /todos/{id}',
  create  : 'POST /todos',
  update  : 'PUT /todos/{id}',
  destroy : 'DELETE /todos/{id}'
}, {});

Todo.prototype.description = function() {
    return this.name + " and " + this.complete;
};

Todo.findAll({}, function(todos) {
    todos.each(function(todo) {
        console.log(todo.name, todo.complete);
        console.log(todo.description());
    });
});

var todo = new Todo({name: "mow lawn"});

todo.save();
findAll()
实际上可以获取所有记录,但是
save()
将插入一条空白记录。我怀疑它可能是
CSRF令牌
,但这显示为警告,如果它不想插入记录,它可能根本不会创建任何记录,而不是添加一个名称为空的记录?(我还尝试了
var-todo=new-todo({name:“mow-lawn”,complete:true});
结果也是一样的)

但是Rails服务器在终端上打印为:

Started POST "/todos" for 127.0.0.1 at 2013-04-12 08:16:05 -0700
Processing by TodosController#create as JSON
  Parameters: {"name"=>"mow lawn"}
WARNING: Can't verify CSRF token authenticity
   (0.2ms)  begin transaction
  SQL (0.8ms)  INSERT INTO "todos" ("complete", "created_at", "name", "updated_at") 
VALUES (?, ?, ?, ?)  [["complete", nil], ["created_at", Fri, 12 Apr 2013 15:16:05 UTC 
+00:00], ["name", nil], ["updated_at", Fri, 12 Apr 2013 15:16:05 UTC +00:00]]
   (1.5ms)  commit transaction
Completed 201 Created in 11ms (Views: 1.3ms | ActiveRecord: 2.5ms)
在Chrome开发者工具中,我在网络中看到:

Request URL:http://localhost:3000/todos
Request Method:POST

part of header:
Content-Type:application/x-www-form-urlencoded; charset=UTF-8

form data:
name:mow lawn
如果我的行动是:

  def create
    p "params[:todo] is", params[:todo]
    @todo = Todo.new(params[:todo])

    respond_to do |format|
      if @todo.save
        format.html { redirect_to @todo, notice: 'Todo was successfully created.' }
        format.json { render json: @todo, status: :created, location: @todo }
      else
        format.html { render action: "new" }
        format.json { render json: @todo.errors, status: :unprocessable_entity }
      end
    end
  end
然后,终端将显示:

"params[:todo] is"
nil
即使终端显示标准Rails日志:

Parameters: {"name"=>"mow lawn"}

如Rails控制台输出所示,您的
params
Hash如下所示:

Parameters: {"name"=>"mow lawn"}
@todo = Todo.new(params[:todo])
但您的控制器正在使用以下命令创建新的Todo实例:

Parameters: {"name"=>"mow lawn"}
@todo = Todo.new(params[:todo])
:todo
不在
params
散列中,因此
params[:todo]
nil
,基本上,您的todo实例没有传递给它的属性,因此它正在为数据库中的
name
列保存
nil

您的控制器应该用来解决这个问题,它将把所有
params
散列包装成
params[:todo]
子散列。因此,如果控制器中有此项:

class TodosController < ApplicationController
  wrap_parameters :todo
  ...
end

然后您现有的操作代码应该可以工作。

就像斯图尔特M所说的,您需要在控制器中设置
wrap\u参数:todo

但是
wrap\u参数:todo
不适用于默认的
内容类型:application/x-www-form-urlencoded
canjs在模型更新时发送

以下是让我解决这个问题的资源:

因此,通过阅读这些内容,我将我的应用程序更改为:

app/controllers/todo_controller.rb

class TodosController < ApplicationController
  wrap_parameters :todo

  def create
    Todo.new(params[:todo])
  end

end
SomeTodoApp::Application.routes.draw do

  resources :todos, except: [:new, :edit]

  match "*all" => "application#cors_preflight_check", via: :options

end
class ApplicationController < ActionController::API

# protect_from_forgery is always a good thing if you know your clients can support get it working

  protect_from_forgery

  before_filter :cors_preflight_check
  after_filter :cors_set_access_control_headers

# For all responses in this controller, return the CORS access control headers.

  def cors_set_access_control_headers
    headers['Access-Control-Allow-Origin'] = '*'
    headers['Access-Control-Allow-Methods'] = 'POST, PUT, PATCH, GET, OPTIONS'
    headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
    headers['Access-Control-Request-Method'] = '*'
    headers['Access-Control-Max-Age'] = "1728000"
  end

# If this is a preflight OPTIONS request, then short-circuit the
# request, return only the necessary headers and return an empty
# text/plain.

  def cors_preflight_check
    if request.method == :options
      headers['Access-Control-Allow-Origin'] = '*'
      headers['Access-Control-Allow-Methods'] = 'POST, PUT, PATCH, GET, OPTIONS'
      headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
      headers['Access-Control-Request-Method'] = '*'
      headers['Access-Control-Max-Age'] = '1728000'
      render :text => '', :content_type => 'text/plain'
    end
  end

end
一切都像魔法一样运作:)


注意:您可能需要设置CORS才能使其工作,以下是如何在公共api上设置它:

config/routes.rb

class TodosController < ApplicationController
  wrap_parameters :todo

  def create
    Todo.new(params[:todo])
  end

end
SomeTodoApp::Application.routes.draw do

  resources :todos, except: [:new, :edit]

  match "*all" => "application#cors_preflight_check", via: :options

end
class ApplicationController < ActionController::API

# protect_from_forgery is always a good thing if you know your clients can support get it working

  protect_from_forgery

  before_filter :cors_preflight_check
  after_filter :cors_set_access_control_headers

# For all responses in this controller, return the CORS access control headers.

  def cors_set_access_control_headers
    headers['Access-Control-Allow-Origin'] = '*'
    headers['Access-Control-Allow-Methods'] = 'POST, PUT, PATCH, GET, OPTIONS'
    headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
    headers['Access-Control-Request-Method'] = '*'
    headers['Access-Control-Max-Age'] = "1728000"
  end

# If this is a preflight OPTIONS request, then short-circuit the
# request, return only the necessary headers and return an empty
# text/plain.

  def cors_preflight_check
    if request.method == :options
      headers['Access-Control-Allow-Origin'] = '*'
      headers['Access-Control-Allow-Methods'] = 'POST, PUT, PATCH, GET, OPTIONS'
      headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
      headers['Access-Control-Request-Method'] = '*'
      headers['Access-Control-Max-Age'] = '1728000'
      render :text => '', :content_type => 'text/plain'
    end
  end

end
app/controllers/application\u controller.rb

class TodosController < ApplicationController
  wrap_parameters :todo

  def create
    Todo.new(params[:todo])
  end

end
SomeTodoApp::Application.routes.draw do

  resources :todos, except: [:new, :edit]

  match "*all" => "application#cors_preflight_check", via: :options

end
class ApplicationController < ActionController::API

# protect_from_forgery is always a good thing if you know your clients can support get it working

  protect_from_forgery

  before_filter :cors_preflight_check
  after_filter :cors_set_access_control_headers

# For all responses in this controller, return the CORS access control headers.

  def cors_set_access_control_headers
    headers['Access-Control-Allow-Origin'] = '*'
    headers['Access-Control-Allow-Methods'] = 'POST, PUT, PATCH, GET, OPTIONS'
    headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
    headers['Access-Control-Request-Method'] = '*'
    headers['Access-Control-Max-Age'] = "1728000"
  end

# If this is a preflight OPTIONS request, then short-circuit the
# request, return only the necessary headers and return an empty
# text/plain.

  def cors_preflight_check
    if request.method == :options
      headers['Access-Control-Allow-Origin'] = '*'
      headers['Access-Control-Allow-Methods'] = 'POST, PUT, PATCH, GET, OPTIONS'
      headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
      headers['Access-Control-Request-Method'] = '*'
      headers['Access-Control-Max-Age'] = '1728000'
      render :text => '', :content_type => 'text/plain'
    end
  end

end
class ApplicationController'',:content\u type=>'text/plain'
结束
结束
结束

您的Rails控制器操作代码是什么样子的?它只是一个标准的脚手架。。。但是我在上面加了代码是的我也看到了。。。所以问题是,是Can.js做得正确还是Rails做得正确?但有一件事是,如果我们发布到/todos,为什么还要发布一个完整的对象,比如
todo:{name:…,complete:…}
vs just
name:。。。,完成:…
?Rails控制台输出中的
参数:
是否发生了变化?关于为什么参数包装会有帮助的解释,请参阅,我相信can.js正确地发送了文章,只需要在接收端(服务器端)对其进行正确的解释。您也可以潜在地使用
Todo.new(params)
,但您可能会从请求中包含额外的元参数,例如
\u方法
或其他不属于模型的参数我尝试过
wrap\u参数
wrap\u参数:Todo
wrap\u参数:Todo,:include=>[:name,:complete]
wrap\u参数:include=>[:name,:complete]
并重新启动服务器,记录仍然为空,它将打印
参数:{“name”=>“mow lawn 76391”,“complete”=>“true”}
。我能让它工作的唯一方法是
@todo=todo.new(:name=>params[:name],:complete=>params[:complete])
,但我仍然对如何使用
wrap_参数感兴趣