Rails 4.2.5 link_to delete method - ruby-on-rails

I have problem with a nested delete method for a link_to helper.
Here are my routes:
resources :restaurants, only: [:new, :show, :edit, :index,:create] do
resources :reservations, only: [:new, :show, :edit, :index, :create]
resources :reviews
end
Here is my review controllers action:
def destroy
#review = Review.find(params[:id])
#review.destroy
end
and my code on user#show:
<div class="panel-body">
<h1> <%= pluralize(#user.reviews.count ,'review') %> from <%= #user.name %> </h1>
<% #user.reviews.order(created_at: :desc).each do |review| %>
<ul>
<li><em>Review for restaurant: </em><%= review.restaurant.name %></li>
<em>Review comment: </em> <%= review.comment %></br>
<%= link_to 'edit comment', edit_restaurant_review_path(review.restaurant_id, review.id) %>
<%= link_to 'delete comment', restaurant_review_path( #user, review.id ) , method: :delete, data:{confirm:"are you sure you want to delete this review"} %>
</ul>
<% end %>
</div>
Here is my route:
restaurant_reviews GET /restaurants/:restaurant_id/reviews(.:format) reviews#index
POST /restaurants/:restaurant_id/reviews(.:format) reviews#create
new_restaurant_review GET /restaurants/:restaurant_id/reviews/new(.:format) reviews#new
edit_restaurant_review GET /restaurants/:restaurant_id/reviews/:id/edit(.:format) reviews#edit
restaurant_review GET /restaurants/:restaurant_id/reviews/:id(.:format) reviews#show
PATCH /restaurants/:restaurant_id/reviews/:id(.:format) reviews#update
PUT /restaurants/:restaurant_id/reviews/:id(.:format) reviews#update
DELETE /restaurants/:restaurant_id/reviews/:id(.:format) reviews#destroy
I can't seem to delete my reviews. Am I passing in the wrong variables?
to 'restaurant_review_path'? My route seems to be right. as my edit link_to helper is working.

restaurant_review_path( #user, review.id ) is wrong. You're passing #user as the restaurant argument, which is going to produce a link with the wrong ID.
You should be giving it a restaurant (or restaurant ID) and a review, not a user and a review id, just like you're doing on the previous line with the edit link.
restaurant_review_path(review.restaurant_id, review.id)

Related

The action 'destroy' could not be found for ListingsController

UPDATE - I'VE NOW SOLVED THIS PROBLEM - I created a partial for the each Course item and rendered them from the main listing view. Thanks for all your help, I'm not really sure why it worked but it did END OF UPDATE
Apologies if this looks like a repeat posting but I've tried applying solutions to similar questions and they haven't worked, I'm stuck! Any suggestions welcomed, thank you.
Problem
I have a 'Courses' model which belongs to a 'Listings' model. The courses are created and deleted on a page belonging to Listing i.e. "/listing/2/courses"
Error Message
No route matches [DELETE] "/listings/2/courses"
Courses Controller def destroy detail
class CoursesController < ApplicationController
before_action :authenticate_user!, except: [:show]
before_action :set_listing
before_action :set_course, except: [:index, :new, :create]
def destroy
#course = #listing.courses.find(params[:id])
#course.destroy
flash[:notice] = "Course deleted!"
redirect_back(fallback_location: request.referer)
end
private
def set_course
#listing = Listing.find(params[:listing_id])
#course = Course.find(params[:id])
end
def set_listing
#listing = Listing.find(params[:listing_id])
end
def course_params
params.require(:course).permit(:name, :curriculum_type, :summary, :address, :course_places, :start_date, :finish_date, :price)
end
end
listing/listingID/courses page detail
<%= #listing.courses.each do |f| %>
<div class="jumbotron">
<ul>
<li>Name = <%= f.name %></li>
<li>Type of course = <%= f.curriculum_type %></li>
<li>Number of places = <%= f.course_places %></li>
<li>Start Date = <%= f.start_date %></li>
<li>Finish Date = <%= f.finish_date %></li>
<li>Price (£) = <%= f.price %></li>
<%= link_to "Delete Course", listing_courses_path(#listing, #course), method: :delete %>
</ul>
</div>
<% end %>
Routes.rb detail
resources :users, only: [:show]
resources :listings, except: [:edit] do
member do
get 'listing'
get 'pricing'
get 'description'
get 'photo_upload'
get 'amenities'
get 'location'
get 'courses'
end
resources :courses, except: [:edit] do
member do
get 'listing'
get 'pricing'
get 'description'
get 'photo_upload'
get 'amenities'
get 'location'
end
end
end
<%= link_to listing_course_path(#listing,f), :method => :delete, :data => { :confirm => 'Are you sure?' } %>
or try
<%= link_to listing_course_path(#listing,id: f.try(:id)), :method => :delete, :data => { :confirm => 'Are you sure?' } %>
route.rb
resources :listings do
resources :courses
end
By default, destroy method expects an ID as it's a member route. You are using listing/listingID/courses route without an ID. For that you need to define listing and/or courses as singular resources (read this) like:
resource :courses do
:
end
as described in this answer or make destroy a collection route like so:
resources :courses, except: [:edit] do
delete :destroy, on: :collection
:
rest...
end
Try and see if this works.
By the way, this looks a bit redundant as you are iterating over each #listing.courses and calling courses#destroy where you are destroying all the courses of #listing anyhow. So, why do #listing.courses.each in the first place. You should have either used a listing#destroy_courses method or remove #listing.courses.each iteration.
Update path in link_to to listing_course_path(#listing, #course) from listing_courses_path(#listing, #course)
<%= link_to "Delete Course", listing_course_path(#listing, f), method: :delete %>

how to display individual listings? Ruby on Rails

I am currently working on a simple website where people can list postings. Most of the code is based on Michael Hartl's tutorial.
I want users to have the ability to click on a link that displays the listing individually.
currently, the listings' of each user are found under
http://localhost:3000/users/id
Every listing has it's own id
Here are my routes
Rails.application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :listings
root 'static_pages#home'
match '/signup', to: 'users#new', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via:'delete'
match '/help', to: 'static_pages#help', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
match '/about', to: 'static_pages#about', via: 'get'
match '/new', to: 'listings#new', via: 'get'
Here is my listing_controller.rb
class ListingsController < ApplicationController
before_action :signed_in_user, only: [:create, :destroy, :edit]
before_action :correct_user, only: :destroy
def create
#listing = current_user.listings.build(listing_params)
if #listing.save
flash[:success] = "Job Post created"
redirect_to current_user
else
render 'listings/new'
end
end
def edit
end
def show
#listing = Listing.find(params[:id])
end
def new
#listing = Listing.new
#listings = Listing.paginate(page: params[:page])
end
def destroy
#listing.destroy
redirect_to current_user
end
private
def listing_params
params.require(:listing).permit(:description, :location, :title)
end
def correct_user
#listing = current_user.listings.find_by(id: params[:id])
redirect_to current_user if #listing.nil?
end
def current_listing
#listings = listing.find(params[:id])
end
end
I also created a show page for each listing under listings the listings folder.
The show page itself works.
Here is the show.html.erb for the listing
<div class="show_listing">
<div class="col-md-6">
<div class="col-md-6">
<h3><%= #listing.title %></h3>
<h3><%= #listing.location %></h3>
<p><%= #listing.description %></p><br>
<div class="center">
<%= link_to "Apply Now", '#', class: "btn btn-info", data: {no_turbolink: true} %>
</div>
</div>
</div>
</div>
<div class="show_link_position">
<% if current_user == #listing.user %>
<%= link_to 'Edit', '#', class: "btn btn-link" %> |
<% end %>
<%= link_to 'Back', current_user, class: "btn btn-link" %>
</div>
Now I would like to have a link on the user page (under each listing) that would link to each post individually.
I'm looking for something like this
how to display a link to individual microposts? (ruby on rails 3)
Thank you
Let me know if you need more information
To create a link from a page where you have the collection of listings as #listings, you might have something like this...
<ol class="listings">
<% #listings.each do |listing| %>
<div class="listing">
<h2><%= listing.title</h2>
<h3><%= listing.location</h3>
<p><%= listing.description</p>
<%= link_to "Show", listing, class: "btn btn-link" %>
</div>
<% end %>
</ol>
Here is what I did to get it to work (with the help of the following stackoverflow post how to display a link to individual microposts? (ruby on rails 3))
Routes rb.
match '/users/:id/:id', to 'listings#show', via: :get, as: :user_listing
users view file
add the link
<li><%= link_to "Show", user_listing_path(id: #user.id, id: listing.id) %></li>
Changed my listing_controller file
def show
#user = User.find_by_id(params[:id])
#listing = Listing.find_by_id(params[:id])
end

Undefined Method 'reviews_path' for #<#<Class:0x3dfd490>:0x51970e0>

References and External Links
Ruby on Rails - Settting up Reviews functionality
NoMethodError in Discussions#new
http://ruby.about.com/od/rubyonrails/ss/blogpart4_4.htm
Background
I'm implementing a feature in my application that allow users to rate and review pictures.
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.
Reviews Migration
class CreateReviews < ActiveRecord::Migration
def change
create_table :reviews do |t|
t.string :username
t.text :body
t.references :picture, index: true
t.timestamps
end
end
end
Matched Routes
match '/pictures/:id/reviews', to: 'reviews#show', via: 'get', :as => 'picture_reviews'
match '/pictures/:id/reviews/edit', to: 'reviews#edit', via: 'get'
match '/pictures/:id/reviews/new', to: 'reviews#new', via: 'get', :as => 'new_reviews'
I will name the route for reviews#edit after I fix this issue with reviews#new.
Error Message
NoMethodError in Reviews#new
Undefined method 'reviews_path' for #<#<Class:0x45c1b00>:0x39ae810>
Extracted source (Around line #8):
5 <div class = 'edit-form'>
6 <div class = 'center'>
7
8 <% form_for #review do |f| %>
9
10 <p>
11 <%= f.label :username %><br />
I checked to see if any files contained 'review-path', but all routes were properly named.
Routes
favorite_picture_path PUT /pictures/:id/favorite(.:format) pictures#favorite
pictures_path GET /pictures(.:format) pictures#index
POST /pictures(.:format) pictures#create
new_picture_path GET /pictures/new(.:format) pictures#new
edit_picture_path GET /pictures/:id/edit(.:format) pictures#edit
picture_path GET /pictures/:id(.:format) pictures#show
PATCH /pictures/:id(.:format) pictures#update
PUT /pictures/:id(.:format) pictures#update
DELETE /pictures/:id(.:format) pictures#destroy
users_path GET /users(.:format) users#index
POST /users(.:format) users#create
new_user_path GET /users/new(.:format) users#new
edit_user_path GET /users/:id/edit(.:format) users#edit
user_path GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
sessions_path POST /sessions(.:format) sessions#create
new_session_path GET /sessions/new(.:format) sessions#new
session_path DELETE /sessions/:id(.:format) sessions#destroy
contacts_path POST /contacts(.:format) contacts#create
new_contact_path GET /contacts/new(.:format) contacts#new
root_path GET / pictures#welcome
users_new_path GET /users/new(.:format) users#new
about_path GET /about(.:format) pictures#about
GET /contacts(.:format) contacts#new
GET /users/:id/favorites(.:format) users#favorites
signup_path GET /signup(.:format) users#new
signin_path GET /signin(.:format) sessions#new
signout_path DELETE /signout(.:format) sessions#destroy
picture_reviews_path GET /pictures/:id/reviews(.:format) reviews#index
GET /pictures/:id/reviews/edit(.:format) reviews#edit
new_reviews_path GET /pictures/:id/reviews/new(.:format) reviews#new
updated_path GET /updated(.:format) pictures#new_updates
GET /top-rated(.:format) pictures#high_ratings
ReviewsController (Part 1)
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :edit, :update, :destroy]
def index
#picture = Picture.find(params[:id])
#review = Review.all
end
def show
#picture = Picture.find(params[:id])
#review = Review.find(params[:id])
end
def new
#review = Review.new
end
def edit
#picture = Picture.find(params[:picture_id])
#review = Review.find(params[:id])
end
def create
#picture = Picture.find(params[:picture_id])
#review = #picture.reviews.build(params[:review])
if #review.save
flash[:notice] = 'Review was successfully created.'
redirect_to #picture
else
flash[:notice] = "Error creating review: #{#review.errors}"
redirect_to #picture
end
end
Reviews Controller(Part 2)
def update
#picture = Picture.find(params[:picture_id])
#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
def destroy
#picture = Picture.find(params[:picture_id])
#review = Review.find(params[:id])
#review.destroy
redirect_to(#review.post)
end
private
def set_review
#review = Review.find(params[:id])
end
def review_params
params.require(:review).permit(:username, :body, :picture_id)
end
end
Reviews#Index Page
<h3>Reviews for <%= "#{#picture.title}" %></h3>
<table>
<thead>
</thead>
<tbody>
</tbody>
</table>
<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>
Link to the Reviews#new page
<p><%= link_to 'New Review', new_reviews_path(#review), :class => "btn btn-info" %></p>
Reviews#New Page
<% #title = "New Review" %>
<h3>New Review</h3>
<div class = 'edit-form'>
<div class = 'center'>
<% form_for #review do |f| %>
<p>
<%= f.label :username %><br />
<%= f.text_field :username %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit "Submit Review" %>
</p>
<% end %>
</div>
</div>
<div class = 'center'>
<%= link_to 'Back', picture_reviews_path(#picture) %>
</div>
Pictures#Show Page
<% #title = "#{#picture.title}" %>
<h4 class = 'indent'>Picture Statistics</h4>
<ul id = 'view'>
<li><strong>Title:</strong> <%= #picture.title %></li>
<li><strong>Category:</strong> <%= #picture.category %></li>
<li><strong>Rating:</strong> <%= pluralize(#picture.rating, 'Star') %></li>
<li><strong>Favorited:</strong> By <%= pluralize(#picture.users.count, 'User') %></li></br>
</ul>
<% if #picture.rating > 4 %>
<button class = 'top-picture'>Top Rated</button>
<% end %>
<%= form_for #picture do |f| %>
<div class = 'indent'>
<p>
<%= f.label :stars, 'Rating' %>
<div class= "rating">
1 ☆<%= f.radio_button :stars, '1' %>
2 ☆<%= f.radio_button :stars, '2' %>
3 ☆<%= f.radio_button :stars, '3' %>
4 ☆<%= f.radio_button :stars, '4' %>
5 ☆<%= f.radio_button :stars, '5' %>
</div>
</p>
<p><input class="btn btn-info" type="submit" value="Rate"></p>
<p><%= link_to 'Reviews', picture_reviews_path(#picture), :class => "btn btn-info" %></p>
<% end %>
<p><%= link_to 'Index', pictures_path, :class => "btn btn-info" %></p>
</div>
I've tried using nested resources like so
resources :pictures do
put :favorite, on: :member
resources :reviews
end
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :contacts, only: [:new, :create]
That didn't work because It routed my pictures using :picture_id instead of the standard :id field. Since it routed to :picture_id it couldn't find any pictures.
picture_reviews_path GET /pictures/:picture_id/reviews(.:format) reviews#index
GET /pictures/:picture_id/reviews/edit/:id(.:format) reviews#edit
new_reviews_path GET /pictures/:picture_id/reviews/new(.:format) reviews#new
Picture Columns
Picture.column_names
=> ['id', 'title', 'category', 'stars', 'created_at', 'updated_at',
'ratings_count', 'ratings_total']
The problem with nesting routes, is that it calls a path using a column_name not found in the table. That is why I decided to go back to matching routes.
I believe the problem lies in my ReviewsController for which there may be duplicated code.
before_action :set_review, only: [:show, :edit, :update, :destroy]
#review = Review.find(params[:id])
def set_review
#review = Review.find(params[:id])
end
I think I could remove the #review = Review.find line from every method, but my main concern is that the set_review method was defined as a private method so that might not be possible.
Help is greatly appreciated and thanks in advanced.
Update
I think the problem lies in my new action in my ReviewsController.
This is just an extended version of #japed answer.
1. You have no route to the create or update action
Both actions works on POST request, hence url_helpers alone won't tell rails what to do with POST request when it gets it. What you need is to change your routes back to nested resources (it was good the way it was, your issue was caused by another bit of code). So, you need:
resources :pictures do
...
resources :reviews
end
Also remove all other routes for this controller as they may affect your final routes. Remeber to restart your server after changing your routes.
2. The controller:
Firstly, note that there are a lot of repetitions there - you are setting #picture in all the actions. Currently your problem is that it is using params[:id] in some actions and params[:picture_id] in others. It should always be picture_id, id should be reserved to be review's id, as you are inside reviews_controller.
The best way to do this is to create another before_filter which will set up the #picture variable:
class ReviewsContorller < ApplicationController
before_filter :set_picture
# This is perfectly fine, but needs to be executed after :set_picture
before_filter :set_review, only: [:show, :edit, :update, :destroy]
...
private
...
def set_picture
#picture = Picture.find(params[:picture_id])
end
def set_review
#review = picture.reviews.find(params[:id])
end
end
Note that the #review is pulled from #picture association - this is important security check, if you used Review.find instead, all the users are automatically able to view, edit and create new reviews for all the photos, without knowing which photo they are really commenting for. It should not be a great issue in your case, but it is good to get this into the habit.
3. The form:
<% form_for #review do |f| %>
This would seems all right, however imagine you are your application - how would you know what is the correct post url for this form? Rails is quite intelligent framework and it is trying to guess it by the resource supplied. In this case, you pass an instance of Review class, hence it will try to send the from to review_path(#review.id). The problem is, that this path does not exists in your routes, so you will get undefined_method 'review_path' here.
Also note, that the proper route you want is /picture/:picture_id/reviews for new reviews or /picture/:picture_id/review/:idfor existing reviews. Hence rails will need the parent picture object to be passed as well to figure out the rightpicture_id`. You can do this by passing an array of resources, with the one which the form is really for being the last so:
<% form_for [#picture, #review] do |f| %>
This will tell rails to look for picture_reviews_path(#picture.id) for new review or picture_review_path(#picture.id, #review.id) for existing reviews. If you have nested resources in your routes, both of those should exists.
4. Other links
Your current routes defines a named path new_reviews which will not longer exist after you use nested resources - it will be renamed to new_picture_review, so you need to change all the occurrences of new_reviews_path to new_picture_review(#picture)
As you're doing nested routes, you need to find by :picture_id as you've just found
class ReviewsController < ApplicationController
before_action { #picture = Picture.find(params[:picture_id] }
end
As your error says the issue is because reviews_path doesn't exist because you've nested it
So this
<% form_for #review do |f| %>
Wants to change to
<% form_for [#picture, #review] do |f| %>
So that it goes to the picture_reviews_path
Also this
<p><%= link_to 'New Review', new_reviews_path(#review), :class => "btn btn-info" %></p>
Wants to become
<p><%= link_to 'New Review', new_picture_reviews_path(#picture, #review), :class => "btn btn-info" %></p>
Can you use Shallow Nesting Routes? That is, you'll have a nested resource where needed, but when unambiguous you get a shorter path, with just one parameter for the review. You can still find your way back to the picture, using the picture_id in the review.
resources :pictures, shallow: true do
put :favorite, on: :member
resources :reviews, shallow: true
end
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :contacts, only: [:new, :create]
Then, improve the models to help the associations to bind well, with inverse_of:
class Review < ActiveRecord::Base
belongs_to :picture, inverse_of: :reviews
end
class Picture < ActiveRecord::Base
has_many :reviews, inverse_of: :picture
end
This should mean there's only one copy of a picture in memory. And then in the ReviewsController:
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :edit, :update, :destroy]
def index
#picture = Picture.find(params[:id])
# reference #picture.reviews to get all reviews in the view
end
def show
#picture = Picture.find(params[:id])
# use #picture.reviews to get all reviews in the view
end
def new
# where will you get the picture this belongs to?
# Need to collect the picture_id param. and build the associated review
#picture = Picture.find(param[:picture_id])
#review = #picture.reviews.build()
end
def edit
#picture = Picture.find(params[:picture_id])
# use #picture.reviews in the view controller to get the associated reviews
end
def create
#picture = Picture.find(params[:picture_id])
#review = #picture.reviews.build(params[:review])
if #review.save
flash[:notice] = 'Review was successfully created.'
redirect_to #picture
else
flash[:notice] = "Error creating review: #{#review.errors}"
redirect_to #picture
end
end
I think there's one other significant issue. You keep using a piece of code like this:
#review = Picture.find(id)
But that returns zero or more elements. It will help you understand the code better if you reflect that this is, normally, an array:
#reviews = Picture.find(id)
But even better, don't do that. You have the associations. Use them in the view.
#picture.reviews
This will return an array. If zero length, there are no reviews. If non-zero, that's how many review elements there are.
Then you won't make the mistake of picking up an array variable called #review, which appears to be singular (meaning that link_to #review appears to make sense, but will fail), and instead use an array:
<%- #picture.reviews.each do |review| %>
<% link_to review ...%>
Hope that helps!

Form for nested resource: undefined method `model_name' for NilClass:Class

I'm doing an online tutorial and was tasked with implementing a comment resource that is nested under a post resource, which in turn is under a topic resource. I've figured out all of the steps of the exercise except getting the 'comment create' form to show up on post#show. I have been trying for several hours to fix it but keep getting the following error: undefined method "model_name" for NilClass:Class. I have no idea what it is referring to by model_name and in my desperation I even looked at the tutorial's code on GitHub, but I still can't see where I'm making the mistake.
My form is in a partial and the error points to the first line, so I'll paste that code here first:
<%= form_for [topic, post, comment] do |f| %>
<div class="controls">
<%= f.text_area :body, rows: 8 %>
</div>
<div class="control-group">
<div class="controls">
<%= f.submit "Add Comment", class: 'btn' %>
</div>
</div>
<% end %>
I'll post my routes so you can see the nesting:
X::Application.routes.draw do
devise_for :users
resources :topics do
resources :posts, except: [:index] do
resources :comments, only: [:create]
end
end
match "about" => 'welcome#about', via: :get
root to: 'welcome#index'
end
Here is my Comments controller:
class CommentsController < ApplicationController
def new
end
def create
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:post_id])
#comment = current_user.comments.build(params[:comment])
#comment.post = #post
if #comment.save
flash[:notice] = "Comment was saved."
redirect_to #post
else
flash[:error] = "Error! Try again."
render :new
end
end
end
Here is my post#show view (form should be rendering at the bottom):
<h1><%= markdown #post.title %></h1>
<div class="row">
<div class="span8">
<small>
<%= image_tag(#post.user.avatar.tiny.url) if #post.user.avatar? %>
submitted <%= time_ago_in_words(#post.created_at) %> ago by
<%= #post.user.name %>
</small>
<br><br>
<p><%= image_tag(#post.image.url) if #post.image? %></p>
<p><%= markdown #post.body %></p>
</div>
<div class="span2">
<% if can? :edit, #post %>
<%= link_to "Edit Post", edit_topic_post_path(#topic,#post), class: 'btn btn-small' %>
<% end %>
</div>
</div>
<br><br>
<h4>Comments</h4>
<%= render #comments %>
<br>
<%= render :template => "/comments/_form.html.erb", locals: { topic: #topic, post: #post, comment: #comment } %>
I would be SO grateful if anyone could help me with this problem. And let me know if there's any info I should add. Thank you!
Generally from what i have read its not recommended using 3 level nested resources. Could you link to the tutorial you are following?
Anyhow I would suggest using shallow on your routes instead.
resources :topics, shallow: true do
resources :posts, except: [:index], shallow: true do
resources :comments, only: [:create]
end
end
Will give you the following resources, which in return will make it easier to create correct forms in your view.
post_comments POST /posts/:post_id/comments(.:format) comments#create
topic_posts POST /topics/:topic_id/posts(.:format) posts#create
new_topic_post GET /topics/:topic_id/posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
topics GET /topics(.:format) topics#index
POST /topics(.:format) topics#create
new_topic GET /topics/new(.:format) topics#new
edit_topic GET /topics/:id/edit(.:format) topics#edit
topic GET /topics/:id(.:format) topics#show
PATCH /topics/:id(.:format) topics#update
PUT /topics/:id(.:format) topics#update
DELETE /topics/:id(.:format) topics#destroy
Now you should only have to send post_id to your comments form. Read more here I haven't worked much with 3 level nesting but this should give you an idea of how you could make it easier for yourself.
EDIT:
In the create action you should build the comment using #post and then set the user to current_user.
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
#comment.user = current_user
if #comment.save
flash[:notice] = "Comment was saved."
redirect_to #post
else
flash[:error] = "Error! Try again."
render :new
end
end
And now no need for #topic
<%= render :template => "/comments/_form.html.erb", locals: { post: #post, comment: #comment } %>
Add '#comment = Comment.new' to the "show" action of the PostController. It had been defined only in the CommentController "create" action.

No routes match error

Not sure why I'm getting
No route matches {:action=>"edit", :controller=>"documents"}
in a link_to in one of my partials
relevant routes.rb
resources :documents, only: [:create, :destroy, :edit, :update] do
post 'sort' => 'documents#sort', on: :collection
end
I recently just added the edit and update actions and thus my current issues
rake routes =
sort_documents POST /documents/sort(.:format) documents#sort
documents POST /documents(.:format) documents#create
edit_document GET /documents/:id/edit(.:format) documents#edit
document PUT /documents/:id(.:format) documents#update
DELETE /documents/:id(.:format) documents#destroy
The partial with the problem route is just
<%= document.title %>
<%= document.position %>
<%= link_to 'link_to_test', edit_document_path %>
<%= link_to 'Delete', document, method: :delete, remote: true %>
my documents_controller.rb has
edit defined
def edit
#document = current_user.documents.find(params[:id])
end
The error occurs because you forgot to specify the object or its id in the edit_document_path. Try this:
<%= link_to 'link_to_test', edit_document_path(document) %>

Resources