Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 4: No route matches - issue with relationships missing id key

I am hoping someone can help me. I am getting the following issue:

No route matches {:action=>"show", :controller=>"stocks", :stockpile_id=>#<Stock id: 17, stockpile_id: 3, code: "rttrtrt", name: "", description: "", quantity: nil, cost_pence: nil, information: "", created_at: "2013-08-18 19:52:46", updated_at: "2013-08-18 19:52:46">, :id=>nil, :format=>nil} missing required keys: [:id]

When visiting the following URL: /admin/stockpiles/3/stocks/

My routes look like:

scope '/admin' do
  root :to => 'admin#index', :as => 'admin'
  resources :stockpiles,:companies

  scope :path => 'stockpiles/:stockpile_id' do
    resources :stocks
  end
end

The data contained in the error message:

id | stockpile_id |   code   | name | description | quantity | cost_pence | information |         created_at         |         updated_at         
17 |            3 | rttrtrt  |      |             |          |            |             | 2013-08-18 19:52:46.856864 | 2013-08-18 19:52:46.856864

My Stock Model:

class Stock < ActiveRecord::Base
  belongs_to :stockpile
end

Nothing interesting in the Stockpile model, just that it has many stocks..

Here is my controller:

class StocksController < ApplicationController
  before_action :set_stock, only: [:show, :edit, :update, :destroy]

  def index
    @stockpile = Stockpile.find(params[:stockpile_id]) 
    @stocks = @stockpile.stocks.all 
  end

  def show
  end

  def new
    @stockpile = Stockpile.find(params[:stockpile_id])
    @stock = @stockpile.stocks.new
  end

  def edit
  end

  def create
    @stockpile = Stockpile.find(params[:stockpile_id])
    @stock = @stockpile.stocks.new(stock_params)

    if @stock.save
      redirect_to @stock, notice: 'Stock was successfully created.'
    else
      render action: 'new'
    end
  end

  def update
    if @stock.update(stock_params)
      redirect_to @stock, notice: 'Stock was successfully updated.'
    else
      render action: 'edit'
    end
  end

  def destroy
    @stock.destroy
    redirect_to stocks_url, notice: 'Stock was successfully destroyed.'
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_stock
      @stockpile = Stockpile.find(params[:stockpile_id])
      @stock = @stockpile.stocks.find(params[:id])
    end

    # Only allow a trusted parameter "white list" through.
    def stock_params
      params.require(:stock).permit(:code, :name, :description, :quantity, :cost_pence, :information)
    end
end

And here is the view in question:

<div class="page-header">
  <%= link_to new_stock_path(params[:stockpile_id]), :class => 'btn btn-primary' do %>
    <i class="icon-plus icon-white"></i>
    New Stock
  <% end %>
  <h1>Listing stocks</h1>
</div>

<table class="table table-bordered table-striped">
  <thead>
    <tr>
      <th>Stockpile</th>
      <th>Code</th>
      <th>Name</th>
      <th>Description</th>
      <th>Quantity</th>
      <th>Cost pence</th>
      <th>Information</th>
      <th></th>
      <th></th>
      <th></th>
    </tr>
  </thead>

  <tbody>
<% @stocks.each do |stock| %>
    <tr>
      <td><%= stock.stockpile %></td>
      <td><%= stock.code %></td>
      <td><%= stock.name %></td>
      <td><%= stock.description %></td>
      <td><%= stock.quantity %></td>
      <td><%= stock.cost_pence %></td>
      <td><%= stock.information %></td>
      <td><%= link_to 'Show', stock %></td>
      <td><%= link_to 'Edit', edit_stock_path(stock) %></td>
      <td><%= link_to 'Destroy', stock, confirm: 'Are you sure?', method: :delete %></td>
    </tr>
<% end %>
  </tbody>
</table>

Help would be much appreciated - looks like something weird is going on because stockpile_id seems to be set to stock, and there seems to be no stock params or anything - so we get the missing id error.

Thanks.

like image 891
user2708672 Avatar asked Dec 26 '22 22:12

user2708672


1 Answers

It would appear that you need to pass in the stockpile as well as the stock..

 <td><%= link_to 'Show', [@stockpile, stock] %></td>

Should do that.

As opposed to using the scope you can probably just use a nested resource in your routes

  resources :stockpiles  do
      resources :stocks 
  end 

and then you can DRY up your stock controller

  class StocksController < ApplicationController
    before_action :set_stockpile 

    .....
    def set_stockpile 
      @stockpile = Stockpile.find params[:stockpile_id]
    end 
like image 174
Doon Avatar answered Apr 28 '23 04:04

Doon