Mohamad
Mohamad

Reputation: 35349

Routing error when using nested resources

I have a Post and Comment models. Comment belongs to a Post, and it is nested under Post in routes. Comments are posted from Posts#show. My routes look like this:

  resources :posts do
    resources :comments, only: [:create, :edit, :update, :destroy]
  end

If a user submits a comment that fails validation, the URL will look like this:

app.com/posts/:id/comments

If, for any reason, the user decides to hit enter in the address bar, there will be a routing error:

Routing Error
No route matches [GET] "/posts/21/comments"
Try running rake routes for more information on available routes.

This strikes me as some what odd. I understand why the error is happening, but it doesn't seem like it's a good idea for usability. Is there a way to prevent this from happening?

This becomes a bigger issue when doing friendly redirects. When a friendly redirect happens, Rails will redirect to that same URL using a GET request, again causing a routing error.

Upvotes: 0

Views: 92

Answers (3)

Marlin Pierce
Marlin Pierce

Reputation: 10081

If your routes are

resources :posts do
  resources :comments, only: [:create, :edit, :update, :destroy]
end

then the URL for edit would be

app.com/posts/:post_id/comments/:id/edit

where :id is the comment. If validation fails, you should be redirecting back to this URL.

def update
  @post = Post.find(params[:post_id])
  @comment = @post.comments.find(params[:id])

  if @comment.update_attributes(params[:comment])
    redirect_to(edit_post_path(@post))
  else
    redirect_to(edit_post_comment_path(@post, @comment), :notice => "update failed")
  end
end

Better, since you are already at the correct edit URL,

...
  else
    flash[:error] = "Error - could not update comment"
    render :action => "edit"
  end

Upvotes: 1

Pawel
Pawel

Reputation: 944

Not the best but the other solution may be to add comments through nested attributes of post.

Upvotes: 0

Lucca Mordente
Lucca Mordente

Reputation: 1131

I think that the best way to avoid it is to create a route for this case and redirect to wherever make sense for your application. Something like the following:

match "/posts/:id/comments" => redirect {|params| "/posts/#{params[:id]}" }

Instead of that routing error, the user would be redirected to the post page.

Upvotes: 1

Related Questions