当调用Ajax时,update.js.erb为什么不会被执行?

使用Ajax,我执行了PUT调用,然后它会提示相应的javascript:

def update
    @todo = Todo.find(params[:id])

    if @todo.update_attribute(:done, true)
        format.js
        format.html {redirect_to todos_path, :notice => "Your todo item was marked done!"}
    else
        redirect_to todos_path, :notice => "Couldn't update your task"
    end
end

下面是相关的路线:

                     PUT    /todos/:id(.:format)           todos#update

下面是我从事件处理程序发出的Ajax调用:

var _id = $(this).attr('id');
//Actual AJAX call
$.ajax({
      type: "PUT",
      url: "/todos/"+_id,
});

但是,当Ajax调用被执行时,我的update.js.erb中的任何内容都不会被执行。

update.js.erb

<% if @todo.valid? %>
    console.log("in here");
    $(".todones").prepend('<li>hello</li>');
<% else %> 
    console.log("or here");
<% end %>

我得到一个错误:error 500 internal server error服务器日志如下:

Started PUT "/todos/264?_method=PUT" for 127.0.0.1 at 2014-03-18 14:25:11 -0400
Processing by TodosController#update as */*
  Parameters: {"id"=>"264"}
  [1m[36mTodo Load (11.8ms)[0m  [1mSELECT "todos".* FROM "todos" WHERE "todos"."id" = ? LIMIT 1[0m  [["id", "264"]]
  [1m[35m (0.1ms)[0m  begin transaction
  [1m[36mSQL (0.4ms)[0m  [1mUPDATE "todos" SET "done" = ?, "updated_at" = ? WHERE "todos"."id" = 264[0m  [["done", true], ["updated_at", Tue, 18 Mar 2014 18:25:11 UTC +00:00]]
  [1m[35m (1.0ms)[0m  commit transaction
Completed 500 Internal Server Error in 17ms

ArgumentError (too few arguments):
  app/controllers/todos_controller.rb:34:in `format'
  app/controllers/todos_controller.rb:34:in `update'

哪里出问题了——我该怎么解决呢?

According to the stack trace in your log, the problem lies here:

app/controllers/todos_controller.rb:34:in `format'

This is because you're missing the respond_to block in your controller, change it to this:

def update
    @todo = Todo.find(params[:id])

    respond_to do |format|
        if @todo.update_attribute(:done, true)
            format.js
            format.html {redirect_to todos_path, :notice => "Your todo item was marked done!"}
        else
            redirect_to todos_path, :notice => "Couldn't update your task"
        end
    end
end

That should fix it as it looks like the request routing is correct and actually hitting the correct action. Now, though, you'd want to fix the controller further. Specifically, in the event that the @todo fails to update, your else block will respond_to format.js.

1) TodosController#update as /. It should do "as JS" instead. AFAIK, if it is not determinable by controller which request it is - it responds to all of them (html, js).

So in your AJAX request add dataType: script like this:

var _id = $(this).attr('id');
//Actual AJAX call
$.ajax({
      type: "PUT",
      url: "/todos/"+_id,
      dataType: "script"
});

2) Have you tried wrapping format.html and format.js with respond_to block ?

respond_to do |format|
    format.html {redirect_to todos_path, :notice => "Your todo item was marked done!"}
    format.js
end