我正在使用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 token
,但显示为警告,如果它不想插入记录,它可能根本不会创建任何记录,而不是添加名称为的记录没有? (我也试过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"}
答案 0 :(得分:2)
如Rails控制台输出中所示,您的params
哈希如下所示:
Parameters: {"name"=>"mow lawn"}
但您的控制器正在使用以下内容创建一个新的Todo实例:
@todo = Todo.new(params[:todo])
:todo
不在params
哈希中,因此params[:todo]
为nil
,基本上您的Todo实例没有传递给它的属性,因此它正在保存{{1}数据库中的nil
列。
您的控制器应使用parameter wrapping来解决此问题,这会将所有name
哈希包装到params
子哈希中。所以如果你在你的控制器中有这个:
params[:todo]
在执行操作之前,您的class TodosController < ApplicationController
wrap_parameters :todo
...
end
哈希将转换为以下内容:
params
然后您现有的操作代码应该有效。
答案 1 :(得分:0)
如 Stuart M 所说,您需要在控制器中设置wrap_parameters :todo
。
但是wrap_parameters :todo
无法使用默认的Content-Type: application/x-www-form-urlencoded
canjs发送模型更新。
以下资源让我解决了这个问题:
https://github.com/bitovi/canjs/issues/111
通过阅读那些我改变我的应用程序看起来像这样:
应用/控制器/ todo_controller.rb 强>
class TodosController < ApplicationController
wrap_parameters :todo
def create
Todo.new(params[:todo])
end
end
应用/资产/ Javascript角/ canjs.models.js 强>
$.ajaxPrefilter(function(options, originalOptions, jqXHR){
if( options.processData && /^(post|put|patch|delete)$/i.test( options.type ))
{
options["contentType"] = "application/json";
options["data"] = JSON.stringify(originalOptions["data"]);
}
});
Todo = Model.new({
...
});
一切都像魔术一样:)
注意:您可能需要设置CORS才能使用此功能,以下是如何在公共API上进行设置:
<强>配置/ routes.rb中强>
SomeTodoApp::Application.routes.draw do
resources :todos, except: [:new, :edit]
match "*all" => "application#cors_preflight_check", via: :options
end
应用/控制器/ application_controller.rb 强>
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