1

I'm trying to figure out how to toggle a "finish" action with nested resources in rails. For whatever reason I can't get it to do what I want. I keep getting 'Couldn't find List without an ID'. Which makes sense but I can't configure it so that it will work. Was curious if anyone knew how to configure things as to get this to function properly. I'm assuming it probably has something to do with my routes file or the each block maybe?? in the partial. Thanks.

Code Below.

Books Controller

def finish
  @list = List.find(params[:list_id])
  @book = @list.books.find(params[:id])
  @book.update(finished: true)
    respond_to do |format|
        format.html {redirect_to list_path(@list)}
        format.js {}
    render @list
end
end

def unfinish
  @list = List.find(params[:list_id])
  @book = @list.books.find(params[:id])
  @book.update(finished: false)
    respond_to do |format|
        format.html {redirect_to list_path(@list)}
        format.js {}
    render @list
 end
end

Books Partial

 <table class="table table-hover">
<thead>
  <tr>
    <th>Title</th>
    <th>Author</th>
    <th>Pages</th>
    <th>Did you finish the book?</th>
    <th>Remove book from list</th>
  </tr>
</thead>
  <tbody>
    <% @books.each do |book| %>
      <tr>
        <td><%=book.name %></td>
        <td><%=book.author %></td>
        <td><%=book.pages %></td>
        <% if book.finished? %>
        <td class="unfinish-book"><%=link_to 'Finished',      unfinish_book_path(book), :method => :put, remote: true %></td>
    <% else %>
    <td class="finish-book"><%=link_to 'Mark as Finished', finish_book_path(book), :method => :put, remote: true %></td>
    <% end %>
    <td class><%= link_to '|Remove Book|', list_book_path(@list, book), method: :delete, data: { confirm: 'Are you sure?'} %></td>
<% end %>
  </tr>
  </tbody>
  </table>

Routes

 Rails.application.routes.draw do
   root 'lists#index'

   resources :lists do
     resources :books
   end

  resources :books do
    member do
      put :finish
      put :unfinish
    end
  end
 end
Mark Hustad
  • 169
  • 1
  • 14
  • 1
    For what it's worth, you do not need to create a special method for this. Simply pass your attributes in a `put/patch` link to your controller's normal `update` method and it will work. – Wes Foster Dec 28 '15 at 22:17
  • Thanks for the advice. I've come back to this app after being away awhile. Can't honestly remember why I did it the way I did. – Mark Hustad Dec 29 '15 at 02:34

1 Answers1

1

If you look at your rake routes output then you'll see the following finish/unfinish routes:

  finish_book PUT    /books/:id/finish(.:format)   books#finish
unfinish_book PUT    /books/:id/unfinish(.:format) books#unfinish

As you can see, there is no :list_id parameter in those URLs, only the :id parameter, so params[:list_id] in your controller code will have no value, hence the error you're getting.

You should probably have those finish/unfinish routes inside the nested books resource, like so:

resources :lists do
  resources :books do
    member do
      put :finish
      put :unfinish
    end
  end
end

Then adjust your link_to calls to send: finish_list_book_path(@list, book) and the unfinish equivalent.

smathy
  • 26,283
  • 5
  • 48
  • 68
  • 1
    Good advice. I was thinking I had already tried that and after looking at your example I realized I had forgotten the 'do' after 'resources :books'. Dang, always the smallest things. Appreciate the help. – Mark Hustad Dec 29 '15 at 02:21