0
votes

I am working on an edit page which works. However, when I click the save button to save the changes I make, in rails 4, I get the following message: No route matches [PATCH] "/book.17" Any advice on how to fix this? I have been researching for a while and believe that it has something to do with my routes and not directing to the right page. Just not sure how I should change it. I have tried using patch/put instead of get for my edit action or putting patch 'books#update' to update but get the same error message. Any help will be appreciated! Here is the code:

Controller:

class BooksController < ApplicationController

def new
 #@book = Book.all
 @book = Book.new 
 @authors = Author.all
end

def edit 
  @book = Book.find_by_id(params[:id])
  @authors = Author.all
end 

def update 
 @book = Book.find_by_id(params[:id])
  if @book.update_attributes(book_params)
   flash[:success] = "Book Updated!"
   redirect_to @book
  else
      render 'edit'
  end 
end 

Routes Page:

Rails.application.routes.draw do

root 'welcome#index'

get 'author' => 'authors#new'

get 'name' => 'authors#show'

get 'book' => 'books#new'

get 'show' => 'books#show'

patch 'edit' => 'books#update'

resources :authors

resources :books

Edit Page:

<div class="move">
<h1>Update a book entry</h2>

<div class="row">
<div class="col-md-6 col-md-offset-3">

<%= form_for(@book)  do |f| %>
  <%= render 'form' %>

  <div class="form-group">
    <%= f.label :title %>
    <%= f.text_field :title, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :pub_date %>
    <%= f.text_field :pub_date, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :publisher %>
    <%= f.text_field :publisher, class: 'form-control' %><br />
  </div>

  <div class="form-group">
    <%= f.select(:author_id, @authors.collect {|a| 
   [ a.name, a.id ]}, {:include_blank => 'Please select an author'}, 
   class: "form-control") %><br />
  </div>

  <%= f.submit 'Save Changes', class: "btn btn-primary" %> 

  <% end %>
  </div>
  </div>
  </div>

Finally, my rake routes:

Rake routes
 Prefix Verb   URI Pattern                 Controller#Action
   root GET    /                           welcome#index
 author GET    /author(.:format)           authors#new
   name GET    /name(.:format)             authors#show
   book GET    /book(.:format)             books#new
   show GET    /show(.:format)             books#show
   edit GET    /edit(.:format)             books#edit
  books GET    /books(.:format)            books#index
        POST   /books(.:format)            books#create
  new_book GET    /books/new(.:format)        books#new
  edit_book GET    /books/:id/edit(.:format)   books#edit
        GET    /books/:id(.:format)        books#show
        PATCH  /books/:id(.:format)        books#update
        PUT    /books/:id(.:format)        books#update
        DELETE /books/:id(.:format)        books#destroy
  authors GET    /authors(.:format)          authors#index
        POST   /authors(.:format)          authors#create
  new_author GET    /authors/new(.:format)      authors#new
  edit_author GET    /authors/:id/edit(.:format) authors#edit
        GET    /authors/:id(.:format)      authors#show
        PATCH  /authors/:id(.:format)      authors#update
        PUT    /authors/:id(.:format)      authors#update
        DELETE /authors/:id(.:format)      authors#destroy

Here is what my log is saying:

Started PATCH "/book.18" for ::1 at 2015-08-15 16:32:10 -0400

ActionController::RoutingError (No route matches [PATCH] "/book.18"): actionpack (4.2.1) lib/action_dispatch/middleware/debug_exceptions.rb:21:in call' web-console (2.2.1) lib/web_console/middleware.rb:39:incall' actionpack (4.2.1) lib/action_dispatch/middleware/show_exceptions.rb:30:in call' railties (4.2.1) lib/rails/rack/logger.rb:38:incall_app' railties (4.2.1) lib/rails/rack/logger.rb:20:in block in call' activesupport (4.2.1) lib/active_support/tagged_logging.rb:68:inblock in tagged' activesupport (4.2.1) lib/active_support/tagged_logging.rb:26:in tagged' activesupport (4.2.1) lib/active_support/tagged_logging.rb:68:intagged' railties (4.2.1) lib/rails/rack/logger.rb:20:in call' actionpack (4.2.1) lib/action_dispatch/middleware/request_id.rb:21:incall' rack (1.6.4) lib/rack/methodoverride.rb:22:in call' rack (1.6.4) lib/rack/runtime.rb:18:incall' activesupport (4.2.1) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'

3
Why do you have all of those extra routes? You should be good with just the resources :authors and resources :books.Beartech
Also, what is your web console saying when you make the request that results in that error. It looks like it is saving and it should redirect to /books/17, but it is getting /book.17. Add your console output to the question.Beartech
As an aside, you don't need Book.find_by_id(params[:id]), you can just say Book.find(params[:id]). find by itself implies id. The other forms of find_by_.... are deprecated in favor of find_by(column_name: 'something').Beartech
I added my log and changed the Book.find_by_id(params[:id]) to Book.find(params[:id]). I also noticed that it is going after /book.17 vice /book/17. Any other help will be appreciated.ravenUSMC

3 Answers

0
votes

Change the route

     patch 'edit' => 'books#update'

to

     patch '/book.:id/' => 'books#update' 

it solves the problem

3
votes

Get rid of those redundant routes, they are just going to mess you up. Rails processes the routes.rb file from the top down, so the order can be screwing you up when you have routes that are basically overriding each other. Just use:

resources :books
resources :authors

This should give you a rake:routes output like:

books_path      GET /books(.:format)    books#index
                POST    /books(.:format)    books#create
new_book_path   GET /books/new(.:format)    books#new
edit_book_path  GET /books/:id/edit(.:format)   books#edit
book_path       GET /books/:id(.:format)    books#show
                PATCH   /books/:id(.:format)    books#update
                PUT /books/:id(.:format)    books#update
                DELETE  /books/:id(.:format)    books#destroy

Controller:

class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
# the above will DRY up your code with a callback

def new
 #@book = Book.all
 @book = Book.new 
 @authors = Author.all
end

def edit 
  @authors = Author.all
end 

def update 
  if @book.update_attributes(book_params)
   flash[:success] = "Book Updated!"
   redirect_to @book
  else
  render 'edit'
  end

private

  # Use callbacks to share common setup or constraints between actions.
  def set_book
    @book = Book.find(params[:id])
  end 
end 
0
votes

Some complicated solutions...

The clue is the malformed url "/book.17" which should read /books/17. You're messing up the rails default url generator up with your routes file entry

patch 'edit' => 'books#update'

because

resources :books 

should already give you an update route. But since it is defined below (after) your manually entered patch route... that's the one that wins so now this line won't work properly in your form for helper. See this for more information

form_for(@user)

Also note the "edit" route in rails is the one that renders the edit view. Its not the one that the edit form submits to, that's the update action. You're kind of trying to do both with

patch 'edit' => 'books#update'

You probably want the book route because you're going OCD on the url scheme, i.e. its only one "book" so url shouldn't say "books". Hold off on that thinking. My advice is until you get the hang of rails better don't fight the conventions, plural routes, etc. Eventually it'll be a piece of cake, but you have a lot more to worry about learning so don't waste your time on the routing conventions. Just drink the kool-aid for a bit and learn the framework.

If you really must have it review this section of the rails routing guide.