Question

I've been staring at this for hours and I know it only a tiny error somewhere but I don't know enough to see it yet.

I used this website to create the first part of the blog and for the last 3 hours I've been trying to add an edit link so users can edit the comments and update.

http://www.reinteractive.net/posts/32

Let the coding begin:

Books Model

class Book < ActiveRecord::Base
  attr_accessible :title
  validates_presence_of :title
  has_many :snippets
  belongs_to :user
  accepts_nested_attributes_for :snippets
end

Snippet (Comment) Model

 class Snippet < ActiveRecord::Base
   belongs_to :book
   belongs_to :user
   attr_accessible :body, :user_id
 end

Snippet Controller

class SnippetsController < ApplicationController   
  before_filter :authenticate_user!, only: [:create]

  def create
    @book = Book.find(params[:book_id])
    @snippet = @book.snippets.create!(params[:snippet])
    redirect_to @book
  end      

  def edit
    @snippet = Snippet.find(params[:book_id])
  end        

  def show
    @book = Book.find(params[:id])
    @snippet = @book.comments.find(:all, :order => 'created_at DESC')
  end    
end

Snippet _form.html.erb

<% form_for([@book, @snippet], :url => edit_book_snippet_path(@book)) %>
  <%= form.error_notification %>

  <div class="form-inputs">
    <%= f.input :title %>
  </div>

  <div class="form-actions">
    <%= f.button :submit %>
  </div>

This is why I cannot understand when I look at the rake routes I get this:

edit_book_snippet GET /books/:book_id/snippets/:id/edit(.:format) snippets#edit

My route is this

> http://localhost:3000/books/3/snippets/12/edit

but my error is still this:

Routing Error

No route matches {:action=>"edit", :controller=>"snippets", :book_id=>nil}

Started learning rails from treehouse but got to intermediate and preferred to learn the harder (but more fun) way.

Help greatly appreciated.

Was it helpful?

Solution

You forgot to specify the book in the edit action of your controller, and since you need it in several actions of your controller, you could create a before_filter callback to make your code more DRY.

For example:

class SnippetsController < ApplicationController   
  before_filter :authenticate_user!, only: [:create]
  before_filter :find_book

  def create
    @snippet = @book.snippets.create!(params[:snippet])
    redirect_to @book
  end      

  def edit
    @snippet = Snippet.find(params[:id])
  end        

  private

  def find_book
    @book = Book.find(params[:book_id])
  end
end

I removed the show action of the controller because it should be used to display one snippet, not all the snippets of a book. To do so, you can use the index action of the SnippetsController, or better, the show action of the BooksController.

One last thing, the url you use in the form declaration is wrong because you need to specify both the book and the snippet:

<%= form_for([@book, @snippet], :url => edit_book_snippet_path(@book, @snippet)) do |f| %>

To get the basis of a blog creation with Rails, I suggest you to read the classic Rails guide.

OTHER TIPS

I think it's not working because in your edit action you have the following

@snippet = Snippet.find(params[:book_id])

but in your _form partial you call @book:

<% form_for([@book, @snippet], :url => edit_book_snippet_path(@book)) %>

in any case the edit_book_snippet_path(@book) is wrong as you should provide both required id's, as the route asks for

books/**:book_id/snippets/**:id/edit

It would be better written like this (although you could also create a before_filter like you have for authenticate user for @book and/or @snippet as you'll probably use them a lot in this controller)

snippet_controller.rb

def edit
  @book = Book.find(params[:id]) 
  @snippet = Book.snippets.find(params[:book_id])
end  

_form.html.erb

<% form_for([@book, @snippet], :url => edit_book_snippet_path(book_id: @book.id, id: @snippet.id)) %>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top