Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No route matches - missing required keys[:id]

Background

I'm implementing a feature in my application that allow users to rate and review pictures.

My problem stems from nesting Reviews resources inside Pictures resources, specifically in my Review#Edit function. The error message specifically declares missing required keys: [:id]

Error Message

ActionController::URLGenerationError in Reviews#Edit
No route matches {:action=>"show", :controller=>"reviews", :format=>nil, :picture_id=>#<Review id: 4, username: "DarkMouse", body: "Updating review", picture_id: 11, created_at: "2014-08-14 03:26:52", updated_at: "2014-08-14 03:55:29">, :id=>nil} missing required keys: [:id]
Undefined method 'reviews_path' for #<#<Class:0x45c1b00>:0x39ae810>
Extracted source (Around line #7):
4 <div class = 'center'>
5   <div class = 'center'>
6 
7     <% form_for [:picture, @review] do |f| %>
8
9      <p>
10        <%= f.label :username, :class => 'marker' %><br /> 

I searched for answers on Stack Overflow.com(My references are given at the bottom) and was advised to do this.

<td><%= link_to 'Edit', edit_picture_review_path(@picture, review) %></td>

Every single solution I came across said to edit the path to include the specific object. If this is any indication, it looks like it really should work.

Parameters

{"picture_id"=>"11",
"id"=>"4"}

Also, my path_url is as follows

http://localhost:3000/pictures/11/reviews/4/edit

The URL path looks similar to my defined routes as well

edit_picture_review_path GET   /pictures/:picture_id/reviews/:id/edit(.:format) reviews#edit

I am using a Posts/Comments relationship model for a Pictures/Reviews relationship.

Models

class Review < ActiveRecord::Base
  belongs_to :picture
end

class Picture < ActiveRecord::Base
  has_many :reviews
end

Above, I established a one-to-many relationship between pictures and reviews.

Routes

favorite_picture_path    PUT   /pictures/:id/favorite(.:format)     pictures#favorite
picture_reviews_pat      GET   /pictures/:picture_id/reviews(.:format)  reviews#index
                         POST  /pictures/:picture_id/reviews(.:format)  reviews#create
new_picture_review_path  GET   /pictures/:picture_id/reviews/new(.:format)  reviews#new
edit_picture_review_path GET   /pictures/:picture_id/reviews/:id/edit(.:format) reviews#edit
pictures_review_path     GET   /pictures/:picture_id/reviews/:id(.:format)  reviews#show
                        PATCH  /pictures/:picture_id/reviews/:id(.:format)  reviews#update
                        PUT    /pictures/:picture_id/reviews/:id(.:format)  reviews#update
                        DELETE /pictures/:picture_id/reviews/:id(.:format)  reviews#destroy

ReviewsController

class ReviewsController < ApplicationController
  before_action :set_review, only: [:show, :edit, :update, :destroy]
  before_filter :find_picture, only: [:index, :create, :edit, :update, :destroy]


  def edit
     @review = Review.find(params[:id])
  end

  def update
    @review = Review.find(params[:id])

    if @review.update_attributes(params[:review])
      flash[:notice] = "Review updated"
      redirect_to @picture
    else
      flash[:error] = "There was an error updating your review"
      redirect_to @picture
    end
  end

  private

    def set_review
      @review = Review.find(params[:id])
    end

   def find_picture
     @picture = Picture.find(params[:picture_id])
   end

    def review_params
      params.require(:review).permit(:username, :body, :post_id)
    end
end

The problem might lie with the review_params

post_id #should be
review_id

Reviews#Index Page

<h3>Reviews for <%= "#{@picture.title}" %></h3>

<table class = "reviews-table">
  <thead>
    <tr>
      <th>Review</th>
      <th>Username</th>
      <th><th>
    </tr>
  </thead>

<tbody>
  <% @picture.reviews.each do |review| %>

    <tr>
      <td><%= review.body %></td>
      <td><%= review.username %></td>
      <td><%= link_to 'Edit', edit_picture_review_path(@picture, review) %></td>
</tr>

<% end %>

<div class = 'center'>
  <p><%= link_to 'New Review', new_reviews_path(@review), :class => "btn btn-info" %></p>
  <p><%= link_to 'Back', picture_path, :class => "btn btn-info" %></p>
</div>

Reviews#Edit Page

<h3>Edit Review</h3>

<div class = 'center'>

<div class = 'center'>

<%= form_for [:picture, @review] do |f| %>

  <p>
    <%= f.label :username, :class => 'marker' %><br />
    <%= f.text_field :username %>
  </p>

  <p>
    <%= f.label :body, "Review", :class => 'marker' %><br />
    <%= f.text_area :body, :rows => "10", :cols => "10" %>
  </p>

  <p>
    <%= f.submit "Submit Review", :class => 'btn btn-success' %>
  </p>

<% end %>

routes.rb

resources :pictures do
  put :favorite, on: :member
  resources :reviews
end

As you can see above, I am using nested resources.

References and External Links

Missing required keys ActionController::UrlGenerationError missing required keys: [:id] No route matches missing required keys: [:id] ActionController::UrlGenerationError: missing required keys: [:id] No routes matches "missing required keys: [:id, :_id]"

All of the above links and more consulted. Every solution tried but none worked. This is why I am re-opening this question. I hope this guide can serve as a template for this problem moving forward.

Thanks in advance. This is not an easy question. Good luck.

like image 622
Darkmouse Avatar asked Aug 14 '14 05:08

Darkmouse


1 Answers

A few observations, off the cuff.

Your error message indicates that No route matches {:action=>"show", :controller=>"reviews". Your ReviewsController does seem to be missing the show action, but that does not seem relevant.

So that leaves us with the offending line:

<% form_for [:picture, @review] do |f| %>

Note, your error is not with this line:

<td><%= link_to 'Edit', edit_picture_review_path(@picture, review) %></td>

Looking at the docs, under Resource-oriented style, we can see the following instruction:

If your resource has associations defined, for example, you want to add comments to the document given that the routes are set correctly:

<%= form_for([@document, @comment]) do |f| %>
 ...
<% end %>

For you, this translates to:

<% form_for [@picture, @review] do |f| %>

The same page also advises:

In the examples just shown, although not indicated explicitly, we still need to use the :url option in order to specify where the form is going to be sent. However, further simplification is possible if the record passed to form_for is a resource, i.e. it corresponds to a set of RESTful routes, e.g. defined using the resources method in config/routes.rb. In this case Rails will simply infer the appropriate URL from the record itself

Although you shouldn't need it, for you this translates to something like:

<% form_for [@picture, @review], url: edit_picture_review_path(@picture, @review) do |f| %>

like image 159
Brad Werth Avatar answered Nov 02 '22 17:11

Brad Werth