Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No route matches [DELETE] for nested resources

I have a nested model setup, where users have multiple manufacturers, and manufacturers have multiple lines. When I try to delete the instance of the line from the line index, I get a bad route message. I'm not sure what I'm doing wrong, but it's probably something simple, was hoping someone could save me some heartache here. I've read the hartl stuff and I'm still very very new to nested resources and routes.

===MODELS===

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  has_many :manufacturers
end

======

class Manufacturer < ActiveRecord::Base
  belongs_to :user
  has_many :lines
end

======

class Line < ActiveRecord::Base
  belongs_to :manufacturer
end

======

lines_controller.rb

class LinesController < ApplicationController
  before_action :set_line, only: [:show, :edit, :update, :destroy]
  before_filter :load_manufacturer

  # GET /lines
  # GET /lines.json
  def index
    @lines = Line.all
  end

  # GET /lines/1
  # GET /lines/1.json
  def show
  end

  # GET /lines/new
  def new
    @manufacturer = Manufacturer.find(params[:manufacturer_id])
    @line = @manufacturer.lines.build
  end

  # GET /lines/1/edit
  def edit
  end

  # POST /lines
  # POST /lines.json
  def create
    @line = @manufacturer.lines.build(line_params)

    respond_to do |format|
      if @line.save
        format.html { redirect_to manufacturer_line_path(@manufacturer, @line), notice: 'Line was successfully created.' }
        format.json { render action: 'show', status: :created, location: @line }
      else
        format.html { render action: 'new' }
        format.json { render json: @line.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /lines/1
  # PATCH/PUT /lines/1.json
  def update
    respond_to do |format|
      if @line.update(line_params)
        format.html { redirect_to manufacturer_line_path(@manufacturer, @line), notice: 'Line was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @line.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /lines/1
  # DELETE /lines/1.json
  def destroy
    @manufacturer.line.destroy
    respond_to do |format|
      format.html { redirect_to lines_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_line
      @line = Line.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def line_params
      params.require(:line).permit(:name, :manufacturer_id)
    end

    def load_manufacturer
      @manufacturer = Manufacturer.find(params[:manufacturer_id])
    end
end

=====

                  Prefix Verb   URI Pattern                                              Controller#Action
      manufacturer_lines GET    /manufacturers/:manufacturer_id/lines(.:format)          lines#index
                         POST   /manufacturers/:manufacturer_id/lines(.:format)          lines#create
   new_manufacturer_line GET    /manufacturers/:manufacturer_id/lines/new(.:format)      lines#new
  edit_manufacturer_line GET    /manufacturers/:manufacturer_id/lines/:id/edit(.:format) lines#edit
       manufacturer_line GET    /manufacturers/:manufacturer_id/lines/:id(.:format)      lines#show
                         PATCH  /manufacturers/:manufacturer_id/lines/:id(.:format)      lines#update
                         PUT    /manufacturers/:manufacturer_id/lines/:id(.:format)      lines#update
                         DELETE /manufacturers/:manufacturer_id/lines/:id(.:format)      lines#destroy
           manufacturers GET    /manufacturers(.:format)                                 manufacturers#index
                         POST   /manufacturers(.:format)                                 manufacturers#create
        new_manufacturer GET    /manufacturers/new(.:format)                             manufacturers#new
       edit_manufacturer GET    /manufacturers/:id/edit(.:format)                        manufacturers#edit
            manufacturer GET    /manufacturers/:id(.:format)                             manufacturers#show
                         PATCH  /manufacturers/:id(.:format)                             manufacturers#update
                         PUT    /manufacturers/:id(.:format)                             manufacturers#update
                         DELETE /manufacturers/:id(.:format)                             manufacturers#destroy
        new_user_session GET    /users/sign_in(.:format)                                 devise/sessions#new
            user_session POST   /users/sign_in(.:format)                                 devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)                                devise/sessions#destroy
           user_password POST   /users/password(.:format)                                devise/passwords#create
       new_user_password GET    /users/password/new(.:format)                            devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format)                           devise/passwords#edit
                         PATCH  /users/password(.:format)                                devise/passwords#update
                         PUT    /users/password(.:format)                                devise/passwords#update
cancel_user_registration GET    /users/cancel(.:format)                                  devise/registrations#cancel
       user_registration POST   /users(.:format)                                         devise/registrations#create
   new_user_registration GET    /users/sign_up(.:format)                                 devise/registrations#new
  edit_user_registration GET    /users/edit(.:format)                                    devise/registrations#edit
                         PATCH  /users(.:format)                                         devise/registrations#update
                         PUT    /users(.:format)                                         devise/registrations#update
                         DELETE /users(.:format)                                         devise/registrations#destroy
                    root GET    /                                                        pages#home
                   about GET    /about(.:format)                                         pages#about
                         GET    /users/:id(.:format)                                     users#show
               all_users GET    /users(.:format)                                         users#index
          public_profile GET    /users/:name(.:format)                                   users#show

======

app/views/lines/index.html.erb

<h1>Listing lines</h1>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Manufacturer</th>
      <th></th>
      <th></th>
      <th></th>
    </tr>
  </thead>

  <tbody>
    <% @lines.each do |line| %>
      <tr>
        <td><%= line.name %></td>
        <td><%= line.manufacturer_id %></td>
        <td><%= link_to 'Show', manufacturer_lines_path(line.manufacturer, line) %></td>
        <td><%= link_to 'Edit', edit_manufacturer_line_path(line.manufacturer, line) %></td>
        <td><%= link_to 'Destroy', manufacturer_lines_path, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>
like image 393
momchenr Avatar asked Mar 18 '14 00:03

momchenr


1 Answers

This is attempting to use the wrong route helper:

<td><%= link_to 'Destroy', manufacturer_lines_path, method: :delete, data: { confirm: 'Are you sure?' } %></td>

It should be:

<td><%= link_to 'Destroy', manufacturer_line_path(line.manufacturer, line), method: :delete, data: { confirm: 'Are you sure?' } %></td>

What manufacturer_lines_path is doing is using the routing helper to generate a path such as /manufacturers/1/lines, which is perfectly valid. What's not valid is that this link is making a DELETE request to that route, and if you look in your rake routes output you'll see that you don't have a route for this. You probably only have one for GET and another for POST, but not for DELETE.

So the solution is to use the right path helper, manufacturer_line_path, which takes a Manufacturer object and a Line object and from that it generates a route such as /manufacturers/1/lines/2. Again, looking in the output of rake routes, you'll see that you have a couple of routes defined for this path. A GET, a PUT, a PATCH and a DELETE.

This last route is what's going to be matched when you make a DELETE /manufacturers/1/lines/2 request, and your application's router will route that to LinesController's destroy action, passing in manufacturer_id=1 and id=2 in the parameters.

like image 124
Ryan Bigg Avatar answered Sep 19 '22 04:09

Ryan Bigg