ActionController::UrlGenerationError - missing required keys - ruby-on-rails

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>

Related

Convert an image_tag to a view helper in Rails

So I'm using the following in both my show and index:
<%= image_tag posts.avatar(:large), alt: 'Avatar for #{posts.title}', class: 'img-responsive' %>
Since they are the same in both I'm trying to move them to a view helper. Then in my views I'm putting:
<%= post_image_tag %>
My initial take was the following:
def post_image_tag
image_tag posts.avatar(:large), alt: 'Avatar for #{posts.title}', class: 'img-responsive'
end
I end up with : undefined local variable or method `posts' for #<#:0x007fcdd273e860>
Did you mean? #posts
Cool. So I change it to:
def post_image_tag
image_tag #posts.avatar(:large), alt: 'Avatar for #{posts.title}', class: 'img-responsive'
end
Now I end up with: undefined method `avatar'.
So I decided that it might just be that I'm not referencing it correctly and trying to pull ActiveRecord on a single post so I try:
def post_image_tag
#posts.each do |posts|
image_tag posts.avatar(:large), alt: 'Avatar for #{posts.title}', class: 'img-responsive'
end
end
At this point something FINALLY renders on the page. Except it looks like an HTML nightmare with:
[#<SpudPost id: 1, spud_user_id: 2, title: "The Top ", content: "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transi...", comments_enabled: false, visible: true, published_at: "2018-01-30 14:45:58", created_at: "2018-02-05 17:41:42", updated_at: "2018-02-05 17:41:42", url_name: "the-top", is_news: false, meta_keywords: nil, meta_description: nil, content_format: "HTML", content_processed: nil, blog_key: "blog", custom_author: nil, identifier: "9b0d97c9-6855-4ad6-85ac-cade6012b5de", avatar_file_name: "ice.jpg", avatar_content_type: "image/jpeg", avatar_file_size: 68494, avatar_updated_at: "2018-02-05 17:41:40">,
It goes further repeating the next item and the next, etc. What in the world can I put on the image_tag to make it render correctly? I've also tried changing the view helper in my view to:
<%= raw(post_image_tag)%>
Then I end up with [#, #, #, #]
You took a wrong turn in this rabbit hole. Go back to your first version of the helper and pass the post as parameter
def post_image_tag(post)
image_tag(post.avatar(:large), alt: 'Avatar for #{post.title}', class: 'img-responsive')
end
# this "posts" should really be named "post", since it's a single post,
# not a collection of them.
<%= post_image_tag(posts) %>
The image is for 1 post, so you should name the variable 'post' and not 'posts'. Anyway this is just for clarity and not an error.
You can define a helper that accepts a param:
def post_image_tag post
image_tag post.avatar(:large), alt: 'Avatar for #{post.title}', class: 'img-responsive'
end
and call it this way (assuming post is 1 post):
<%= post_image_tag(post) %>
If you have many posts in #posts, you should do:
<%= #posts.each do |post| %>
<%= post_image_tag(post) %>
<% end %>
You can also make another helper to handle many posts (it may need some changes, but you get the idea):
def posts_image_tag posts
result=''
posts.each do |post|
result += post_image_tag(post)
end
result.thml_safe
end
and call it this way (assuming #posts has all your posts):
<%= posts_image_tag(#posts) %>

Rails, link_to method: :delete breaks after child element (comment) instantiated

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.

Destroying Nested Comments

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 %>

iterate through active record results - ruby on rails

I've been trying got find this answer, and maybe it's too simple...
In rails, how is the best way to iterate through results from activerecord pull the specific fields that you want?
I have a controller for comments (named posts) that pulls all records:
def index
#posts = Post.find(:all)
end
Then in the index view, when I use <%= #posts %> I get all of the data...which is great...
#<Post id: 1, user_id: "9", picture: nil, comments: "here's a first comment", title: nil, twitter: nl, frame: nil, created_at: "2012-05-09 04:21:16", updated_at: "2012-05-09 04:21:16"> #<Post id: 2, user_id: "9", picture: nil, comments: "here's a second comment", title: nil, twitter: "please", frame: nil, created_at: "2012-05-09 05:20:03", updated_at: "2012-05-09 05:20:03">
How can I now iterate through test so that the view shows the data from the comments and created_at fields:
Here's the first comment, 2012-05-09 04:21:16
Here's the second comment, 2012-05-09 05:20:03
I've tried the following and get an error.
<% #posts.each do |c| %>
<%= c.posts.comments %>
<%= c.posts.created_at %>
<% end %>
The "c" in #posts.each do |c| represents the specific post object in the #posts collection.
So, in a sense you are trying to do <%= post.posts.comments %>.
Here's how the code should look:
<% #posts.each do |p| %>
<%= p.comments %>
<%= p.created_at %>
<% end %>
Change things to this:
<% #posts.each do |post| %>
<%= post.comments %>
<%= post.created_at %>
<% end %>
I find it makes it easier for people to follow if you name the inner variable as the singular of the out variable -- therefore #posts on the outside becomes post on the inside.
Good luck!

Ruby on Rails 3 .each do Problem

I'm sort of new to Ruby on Rails and have been learning just fine, but have seem to run into a problem that I can't seem to solve.
Running Rails 3.0.9 & Ruby 1.9.2
I'm running the following statement in my View:
<%= #events.each do |f| %>
<%= f.name %><%= link_to "View", event_path(f) %><br/><hr/>
<% end %>
And this in my controller:
class AdminController < ApplicationController
def flyers
#events = Event.all
end
end
This goes through each of the records and outputs the appropriate name, but the problem is that at the end it displays all of the information for all of the records like so:
[#<User id: 1, username: "test account", email: "test#gmail.com", password_hash: "$2a$10$Rxwgy.0ZEOb0lMGEIliPBeB/jPSp8roeKdbMvXcLi32R...", password_salt: "$2a$10$Rxwgy.0ZEOb0lMGEIliPBe", created_at: 2111359287.2303703, updated_at: 2111359287.2303703, isadmin: true>]
I'm new to this site, so I'm not sure if you need any more details, but any help is appreciated, after all, I'm still learning.
Thanks in advance.
You should be using <%, not <%= for your .each line, so
<%= #events.each do |f| %>
should be
<% #events.each do |f| %>
.each returns the entire array at the end once it is finished the loop.
<%= ... %> prints out the value of the statment, which is the value returned by .each
<% ... %> does not. So you want:
<% #events.each do |f| %>
<%= f.name %><%= link_to "View", event_path(f) %><br/><hr/>
<% end %>

Resources