0

I'm on a video show page (which belongs to a post). The link_to delete works just fine until I create a comment on that video show page. I have a series of capybara tests that validate that the link_to delete video is working until I create a comment on that video at which point rails returns...

Failure/Error: <%= link_to "Delete Video", post_video_path(@video), method: :delete %>

ActionView::Template::Error:
   No route matches

Not sure what's going on here or how to fix it. I stuck a pry in and the first two tests that hit it I checked the path...

post_video_path(@video)

which returned a valid path, e.g.

[1] pry(#<#<Class:0x007f891941dee0>>)> post_video_path(@video)
=> "/posts/1/videos/1"

When the spec instantiates a comment, the path reads as follows...

[1] pry(#<#<Class:0x007f891c2fd0a8>>)> post_video_path(@video)
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"videos", :post_id=>#<Video id: 1, user_id: 1, post_id: 1, title: "18title", url: "https://www.youtube.com/watch?v=tYm_182oCVdSM", embed_id: "https://www.youtube.com/watch?v=tYm_182oCVdSM.spli...", tags: nil, created_at: "2016-10-16 22:12:30", updated_at: "2016-10-16 22:12:30">, :video_id=>"1"} missing required keys: [:id]

videos_controller.rb

def show
  @video = Video.find(params[:id])
  @user = @video.user
  @post = @video.post
  @comment = Comment.new
  @comments = @video.comments
end

videos/show.html.erb

<%= @video.title %>
<%= content_tag(:iframe, nil, src: "//www.youtube.com/embed/#{@video.embed_id}") %>
<% binding.pry %>
<%= link_to "Delete Video", post_video_path(@video), method: :delete %>
<%= link_to('Back', user_post_path(@user, @post)) %>

<h3>Comments</h3>

<%= form_for [@video, @comment] do |f| %>
  <%= f.label(:body, "Comment") %>
  <%= f.text_area(:body) %>
  <%= f.submit("Submit Comment") %>
<% end %>

<% @comments.each do |comment| %>
  <%= comment.body %>
  <%= comment.user %>
<% end %>

routes.rb

Rails.application.routes.draw do
  devise_for :users

  resources :users, only: [] do
    collection do
      get '/show_profile', to: 'users#show_profile', as: 'my_profile'
      get '/show_log', to: 'users#show_log', as: 'my_log'
    end
    resources :posts, only: [:new, :create, :show]
  end

  resources :posts do
    resources :videos
  end

  resources :videos do
    resources :comments
  end

  root 'home#index'
end

models/comment.rb

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :video

  validates :body, presence: true
end

Please let me know if you would like to see any particular file or code.

Thanks!

n.milsht
  • 163
  • 3
  • 17
  • 1
    Welcome to Stack Overflow. Please read "[mcve]". We have to be able to duplicate the problem based on the code and input data you give us. If a coworker walked up with a printed page containing your question, handed it to you, and walked away, could you answer the question? What would you ask for? Add that additional information to your question, because we're either going to ask for that, or we're going to try to guess what it was, and guessing is going to result in wild answers which isn't going to do anyone any good. – the Tin Man Oct 16 '16 at 22:29
  • 1
    Noted. I believe I've added everything relevant. If I'm missing anything, please let me know. – n.milsht Oct 16 '16 at 22:49
  • 1
    Excellent. Thank you! It's really important to dig in and try to find the answer up front, and if you can't then summarize the work you did in your question, and provide enough for us to duplicate your work and move forward. Without that we're left duplicating things you tried, or worse, trying to teach what you should know and should have done! :-) And, BTW, your question will help others who are searching for similar solutions in the future, it's not just to help you now. That's why we ask, and answer. – the Tin Man Oct 16 '16 at 23:09

1 Answers1

0

Generally speaking - when you use a path name that has the names of two models, you need to pass it two models.

eg in your case, your path is post_video_path(@video) - what this expects is for you to pass it a post and a video eg post_video_path(@post, @video)

if you don't... then it will get confused, possibly in a way you didn't expect. In this case, I'm guessing that it's taking the id of the video, and assuming it's the post_id.

You can tell it's confused by look at this error message:

ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"videos", :post_id=>#<Video id: 1, user_id: 1, post_id: 1, title: "18title",

Specifically the part that has: :post_id=>#<Video id: 1, ... -> it's putting the video in the post_id. Quite possibly it only "worked" before because you had a single post, and a single video... and thus when it used the id of 1 from the video as the post-id... the video was already assigned to the post (that also had an id of 1)... but once you delete that one, it no longer exists. This is a total guess - it doesn't matter if this is how Rails got confused, as long as you recognise where the error is coming in.

Taryn East
  • 27,486
  • 9
  • 86
  • 108