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>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With