Question

I have todo list app. In the application there are multiple places wher you can mark a todo done by clicking in a checkbox.

This is the erb

<% @todos.each do |todo|%>
 <%= form_for todo, remote: true do |f| %>
  <%= f.check_box :completed, :class => "dashboard_done_box", :id => todo.id %>
 <% end %>
<% end %>

and here's the js

$(document).on('click', ".dashboard_done_box", function(){
 $("#edit_todo_" + $(this).attr('id')).submit()
});

The routes.rb has the line

resources :todos

When I refresh the page it works, but when I am navigating to it I get this error.

Started POST "/todos/1" for 127.0.0.1 at 2014-05-07 13:18:45 +0200
ActionController::RoutingError (No route matches [POST] "/todos/1"):

It also works when I disable turbolinks.

This code works on other pages in my application it is just on one page I have this problem.

When it works in makes a PATCH request

Started PATCH "/todos/1" for 127.0.0.1 at 2014-05-07 13:44:08 +0200
Processing by TodosController#update as JS

Why does it do a POST request and how is it connected to turbolinks?

Update

Yosep Kim suggested I should make a post route

routes.rb

post 'todos/:id'  => 'todos#update', :as => :todo_update

The form

<%= form_for @todo, remote: true, url: todo_update_path(@todo), method: :post do |f| %>

Now I get trough to the controller, but only with these parameters

{"controller"=>"todos", "action"=>"update", "id"=>"3"}

Conclusion: The form submission is not getting serialized. Why?

Was it helpful?

Solution

How does the form render?

Rails uses the PATCH verb to update because in rails applications a update is almost always a partial update. The PUT verb should be used for complete updates ( like when you overwrite a file ) Read more here Riding With Rails

Rails uses hidden fields to accommodate the html verb.

Your form should render like this

<form accept-charset="UTF-8" action="/todos/5" class="edit_todo" data-remote="true" id="roster_edit_done_todo_5" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="✓">
    <input name="_method" type="hidden" value="patch">
  </div>
 <!-- What ever fields you need -->
</form>

Be aware if you have the form in a table. The table might make the form render strange.

OTHER TIPS

There is a bug on latest 64bit Chrome dev/beta channel version 37,38.

If you use it, see https://code.google.com/p/chromium/issues/detail?id=388664

First of all, your code is creating two redundant requests, when the checkbox is clicked. The first one is fired by the form, and the second by the JS code you have. The one that is fired by the form would ONLY work one time after the page refreshes. Once you click on it, Turbolink would refresh the contents in the BODY without reloading the DOM, failing to attach the AJAX event handler to the form.

You can suppress the default behavior by using preventDefault. This should only fire the action once through the JS code.

$(document).on('click', ".dashboard_done_box", function(e){
 e.preventDefault();
 $("#edit_todo_" + $(this).attr('id')).submit()
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top