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!
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.
Related
I am new to rails and am trying to build my first MVC app. I am trying to create a link file path and get this error message -
ActionController::UrlGenerationError in Pages#my_profile
No route matches {:action=>"show", :car_id=>10, :controller=>"bookings"}, missing required keys: [:id]
This is the code I am using in the view
<% current_user.bookings.each do |booking| %>
<%= link_to booking.car.make, car_booking_path(booking[:id])%></h2>
<% end %>
When I type booking into the rails console I have access to the following hash
#<Booking id: 10, start_date: "2020-08-18", end_date: "2020-08-19", status: nil, user_id: 5, car_id: 5, created_at: "2020-08-18 17:34:41", updated_at: "2020-08-18 17:34:41">
so am unsure as to why, when booking[:id] is passed it is not picked.
my route is
car_booking GET /cars/:car_id/bookings/:id(.:format) bookings#show
Does anyone have any idea on what I am missing?
any help would be massively appreciated.
Try:
<% current_user.bookings.each do |booking| %>
<%= link_to booking.car.make, [booking.car, booking] %></h2>
<% end %>
See, you have a nested route:
car_booking GET /cars/:car_id/bookings/:id(.:format) bookings#show
Which expects both car_id and id. You're only passing in one value, booking[:id], which is in the first position, so it is interpreted as car_id (although it's actually booking.id). There is no second value in your arguments, so you get the missing required keys: [:id] message.
Note that if you used shallow nesting, something like this:
Rails.application.routes.draw do
...
resources :cars do
resources :bookings, shallow: true
end
...
end
then you would just do:
<% current_user.bookings.each do |booking| %>
<%= link_to booking.car.make, booking_path(booking)%></h2>
<% end %>
Also note that you can typically do booking_path(booking) instead of booking_path(booking.id). In fact, as stated in the docs, you can use the pithier:
<% current_user.bookings.each do |booking| %>
<%= link_to booking.car.make, booking %></h2>
<% end %>
If you don't want to use shallow nesting, you can do:
<% current_user.bookings.each do |booking| %>
<%= link_to booking.car.make, [booking.car, booking] %></h2>
<% end %>
...and, as discussed in the docs Rails will infer the car_booking_path helper.
In your question, you say you have access to the following hash:
#<Booking id: 10, start_date: "2020-08-18", end_date: "2020-08-19", status: nil, user_id: 5, car_id: 5, created_at: "2020-08-18 17:34:41", updated_at: "2020-08-18 17:34:41">
FYI, that's not a hash. That's an instance of the Booking class which inherits from ActiveRecord::Base. To get the id from that instance, do booking.id, not booking[:id].
As per the output from the routes, you need to pass two arguments id and car_id.
Try the below:
<%= link_to booking.car.make, car_booking_path(car_id: booking.car_id, id: booking.id)%></h2>
I am working on an app for rockhounds that will allow them to track the rocks they have found. I am trying to finish a method that will allow users to update rocks. The method itself works if you go to the '/edit' page where you enter a url, but when trying to reach that page via a link from the show page for the rock I get an error:
Param is missing or the value is empty: rock
Its coming from line 43 in my rocks controller, inside the method rock_params. The parameters for this request are:
{"_method"=>"patch", "authenticity_token"=>"tiQQjQCMi6lbDPOxQ2X7fNTamWEZ3EAandGQ1Tv4NJKxieVIUnnWcKh3efd9F2LIRZWBYeC5M3RuEr0/FHQnww==", "id"=>"6"}
Here is my controller code
before_action :find_rock, only: [:show, :edit, :update, :destroy]
def index
#rocks = Rock.all
end
def show
#rock = Rock.find_by(id: params[:id])
end
def new
#rock = Rock.new
end
def create
#rock = Rock.new(rock_params)
if #rock.save
redirect_to #rock
else
render :new
end
end
def update
if #rock.update(rock_params)
redirect_to #rock
else
render :edit
end
end
def destroy
#rock = Rock.find(params[:id])
#rock.destroy
redirect_to rocks_path
end
private
def rock_params
params.require(:rock).permit(:id, :nick_name, :category, :minerals, :outcrop)
end
def find_rock
#rock = Rock.find(params[:id])
end
end ```
Here is the view code for the show page:
`<h1> Rock: </h1>
<h2> Rock Name: <%= #rock.nick_name %></h2>
<h2> Rock Type: <%= #rock.category %></h2>
<h2> Major Minerals: <%= #rock.minerals %></h2>
<h2> Outcrop? : <%= #rock.outcrop %></h2>
<%= link_to "Edit this rock", edit_rock_path(#rock), method: :patch %>
<%= link_to "Delete this rock", rock_path(#rock), method: :delete %> `
and the edit page:
```<%= form_for :rock do |f| %>
Name: <%= f.text_field :nick_name %><br>
Category: <%= f.select :category, ['Igneous', 'Sedimentary', 'Metamorphic'] %><br>
Major Minerals <%= f.text_area :minerals %><br>
Outcrop or Boulder? <%= f.select :outcrop, ['Outcrop', 'Boulder'] %><br>
<%= f.submit %>
<% end %> ```
and here are my routes:
```resources :rocks
resources :users
resources :locations
post '/users/new', to:"users#create"
get '/signup', to:"users#new", as: "signup"
post '/rocks/new', to:"rocks#create"
get '/rocks/:id/edit', to:"rocks#edit"
patch '/rocks/:id/edit', to:"rocks#update"
post '/rocks/:id/destroy', to:"rocks#destroy"
root to: "rocks#index"
get '/login', to: "auth#login", as: "login"
post '/login', to: "auth#authenticate"
get '/logout', to: "auth#logout"```
So the question is **How do I fix the empty param error that occurs when clicking the link to edit a rock from the show page for that rock?**
#toodles from the rails documentation here, edit paths are of the HTTP verb GET.
You need to change this line <%= link_to "Edit this rock", edit_rock_path(#rock), method: :patch %>, remove method: :patch which applies a PUT HTTP verb
It should look like this <%= link_to "Edit this rock", edit_rock_path(#rock) %> as rails applies the GET verb if the method is not specified.
You'll be able to see this when you inspect your link in a browser
Also, since you defined the resource :rocks, you don't need to redefine the other rock routes below it. You can see the generated routes with the rails routes command in your terminal.
You can also add an edit action to your controller, that returns #rock, which you use in the edit page. This section of the getting started with Rails article shows it clearly.
Using a member route like this similar to one I have used for deleting tags:
resources 'factory' do
resources 'tags' do
member do
delete :remove
end
end
resources 'project_files' do
member do
delete :remove
end
end
end
I (should) invoke in the projects controller:
class ProjectFilesController < ApplicationController
def remove
#factory = Factory.find(params[:fabmoment_id])
#project_file = ProjectFile.find(params[:id])
authorize #factory, :project_file?
#project_file.remove!
head :ok
end
end
Which I can't check for correctness (yet). The partial _project_files looks like:
<li class="project_file">
<% if policy(factory).project_file? %>
<%= link_to "<span></span>".html_safe,
remove_factory_project_file_path(factory, project_file), method: :delete, remote: true,
class: "remove",
title: "remove" %>
<% end %>
<%= link_to File.basename(project_file.url), project_file.url %>
(<%= number_to_human_size(project_file.file.size) %>)
</li>
Which is invoked by passing locales with a render method in the factory#show view. (Could also add an index.)
Like this it is mostly equal to the tags remove action though and I like to keep things consequent and simple.
The error I receive from my spec:
No route matches [DELETE] "/factories/1/project_files/%2Fuploads%2Ffactory%2Fproject_files%2F1%2Fthe_puritan_1st_floor.stl/remove"
My Factory model only contains mount_uploaders :project_files, ProjectFileUploader
Any ideas on how to make this work?
Good Morning,
I'm having an issues with nested comments. I have a partial which shows these but I want to add a delete snippet at the bottom of .each one.
Here is the partial:
_snippets.html.erb
<% #snippets.each do |snippet| %>
<%= raw(snippet.content) %>
<% if can? :manage, snippet %>
<%= link_to 'delete', book_snippet_path(snippet), :method => :delete %>
<% end %>
<% end %>
Here are my routes:
book_snippets POST /books/:book_id/snippets(.:format) snippets#create
edit_book_snippet GET /books/:book_id/snippets/:id/edit(.:format) snippets#edit
book_snippet PATCH /books/:book_id/snippets/:id(.:format) snippets#update
PUT /books/:book_id/snippets/:id(.:format) snippets#update
DELETE /books/:book_id/snippets/:id(.:format) snippets#destroy
Here is the stack error, showing no route matches update?
No route matches {:action=>"update", :controller=>"snippets", :id=>nil, :book_id=>#<Snippet id: 4, content: "<p>YACHT!</p>\r\n", book_id: 4, created_at: "2013-11-15 09:12:20", updated_at: "2013-11-15 09:12:25", approved: true, user_id: 1>, :format=>nil} missing required keys: [:id]
I know it's probably something stupid I'm missing but would really like some help figuring this one out.
Thanks :)
You are missing book_id . You routes says
DELETE /books/:book_id/snippets/:id(.:format)
needs a book_id in path. So need to pass #book object as well in the arguments.
<%= raw(snippet.content) %>
<% if can? :manage, snippet %>
<%= link_to 'delete', book_snippet_path(#book, snippet), :method => :delete %>
<% end %>
Noob here.
Trying to figure out how to display a method in my controller into my index page. Here is what I have thus far.
Controller -
class SammichesController < ApplicationController
def index
#sammiches = Sammich.all
end
def create
#sammich = Sammich.find_by_name(params[:sammich][:name])
end
def random
#sammichy = Sammich.rand(params[:sammich][:name])
end
end
Routes-
Sammiches::Application.routes.draw do
resources :sammiches do
get "random"
end
root :to => 'sammiches#index'
Index-
<h1>All my Sammiches</h1>
<%= form_for Sammich.new do |f| %>
<%= f.label :sammich %>
<%= f.text_field :name %>
<%= f.submit 'Find Sammich', :id => 'sammich_submit' %>
<% end %>
<%= link_to "Random sandwich", sammich_random_path %>
routes-
sammich_random GET /sammiches/:sammich_id/random(.:format) sammiches#random
sammiches GET /sammiches(.:format) sammiches#index
POST /sammiches(.:format) sammiches#create
new_sammich GET /sammiches/new(.:format) sammiches#new
edit_sammich GET /sammiches/:id/edit(.:format) sammiches#edit
sammich GET /sammiches/:id(.:format) sammiches#show
PUT /sammiches/:id(.:format) sammiches#update
DELETE /sammiches/:id(.:format) sammiches#destroy
root / sammiches#index
Error-
localhost:3000 - Routing Error
No route matches {:action=>"random", :controller=>"sammiches"}
Try running rake routes for more information on available routes.
Any assistance would be much appreciated.
Thanks!
If you look at your route it has :sammic_id in there as well:
sammich_random GET /sammiches/:sammich_id/random(.:format) sammiches#random
Which means you need to pass an id to your URL helper sammich_random_path which you haven't.
Update your routes to this:
resources :sammiches do
collection do
get "random"
end
end
After adding that your route would be just /sammiches/random