So I have a reviews show page that is nested under albums routes. On a reviews show page, the URL was http://localhost:3000/albums/2/reviews/19, I changed 19 to a random number of a review i don't have. That led me to an error "couldn't find Review with 'id'=25". I would like to redirect that user to my not_found page I created, but I'm not sure how to do that.
Here is my error:
ActiveRecord::RecordNotFound in ReviewsController#show
Couldn't find Review with 'id'=25
Extracted source (around line #59):
57
58
59
60
61
62
def set_review
#review = Review.find(params[:id])
end
def set_current_user
Reviews controller:
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :edit, :update, :destroy]
before_action :set_current_user, only: [:index, :show, :new, :edit, :destroy]
before_action :find_album, only: [:show, :create, :edit, :update, :destroy]
before_action :must_login, only: [:index, :show, :new, :create, :edit, :update, :destroy]
def index
#albums = Album.with_recent_reviews #scope
end
def show
##reviews = Review.where("album_id = ?", params[:album_id])
end
def new
if params[:album_id] && #album = Album.find_by(id: params[:user_id])
#review = #album.reviews.build
else
redirect_to albums_path
end
end
def create
#review = current_user.reviews.build(review_params)
##review.album = #album
if #review.save
redirect_to album_path(#album)
else
##review.album
render :new
end
end
def edit
end
def update
if #review.update(review_params)
redirect_to album_path(params[:album_id])
else
render 'edit'
end
end
def destroy
if current_user.id == #review.user_id
#album.reviews.find(params[:id]).destroy
redirect_to album_path(params[:album_id])
else
flash[:error] = "Unable to delete your review. Please try again."
redirect_to album_reviews_path(#review)
end
end
private
def set_review
#review = Review.find(params[:id])
end
def set_current_user
#user = current_user
end
def find_album
#album = Album.find(params[:album_id])
end
def review_params
params.require(:review).permit(:title, :date, :content, :album_id, album_attributes:[:artist, :title, :user_id])
end
end
REviews show.html.erb:
<h6><strong>
Showing "<%= #review.title %>" for
<%= #album.artist %> -
<%= #album.title %>
</strong></h6>
<br>
<% if #album.avatar.attached? %>
<image src="<%=(url_for(#album.avatar))%>%" style="width:350px;height:350px;">
<% end %>
<br>
<br>
<%= link_to "Edit Album", edit_album_path(#album), class: "waves-effect waves-light btn" %>
<%= link_to 'Delete Album', album_path(#album), method: :delete, class: "waves-effect waves-light btn" %>
<br><br>
<hr>
<% unless #review.id.nil? %>
<small>Date written: <%= #review.date.strftime("%d %B %Y") %></small><br>
<small>Written by: <%= #review.user.name %></small><br>
<br>
<strong>Title: <%= #review.title %></strong><br>
<%= #review.content %><br>
<br>
<% if current_user.id == #review.user_id %>
<%= link_to "Edit Review", edit_album_review_path(album_id: #album.id, id: #review.id), class: "waves-effect waves-light btn" %>
<%= link_to 'Delete', album_review_path(album_id: #album.id, id: #review.id), method: :delete, data: { confirm: 'Are you sure?' }, class: "waves-effect waves-light btn" %><br><br>
<% end %>
<br><br>
<% end %>
<br>
<strong>
<%= link_to "Write a New Review", album_path(#album), class: "waves-effect waves-light btn" %></strong>
<br><br>
rake routes:
GET /auth/:provider/callback(.:format) sessions#omniauth
auth_failure_path GET /auth/failure(.:format) redirect(301, /)
signup_path GET /signup(.:format) users#new
POST /signup(.:format) users#create
signin_path GET /signin(.:format) sessions#new
POST /signin(.:format) sessions#create
signout_path GET /signout(.:format) sessions#destroy
logout_path POST /logout(.:format) sessions#destroy
not_found_path GET /not_found(.:format) pages#not_found
album_reviews_path POST /albums/:album_id/reviews(.:format) reviews#create
new_album_review_path GET /albums/:album_id/reviews/new(.:format) reviews#new
edit_album_review_path GET /albums/:album_id/reviews/:id/edit(.:format) reviews#edit
album_review_path GET /albums/:album_id/reviews/:id(.:format) reviews#show
PATCH /albums/:album_id/reviews/:id(.:format) reviews#update
PUT /albums/:album_id/reviews/:id(.:format) reviews#update
DELETE /albums/:album_id/reviews/:id(.:format) reviews#destroy
pages controller for not_found path
class PagesController < ApplicationController
before_action :current_user
def not_found
end
private
def current_user
super() #looks for same method on what i'm inheriting from (applicationcontroller)
end
end
albums controller:
class AlbumsController < ApplicationController
before_action :set_current_user, only: [:new, :index, :new, :edit]
before_action :set_album, only: [:show, :edit, :update, :destroy]
before_action :must_login, only: [:new, :show, :create, :edit, :update, :destroy]
def index
#albums = Album.all.order("artist ASC")
end
def show
#review = #album.reviews.build
#review.user = current_user
#reviews = Review.recent #scope shows recent reviews
end
def new
#album = Album.new
#review = #album.reviews.build
end
def create
#album = current_user.albums.build(album_params)
#album.reviews.each { |r| r.user ||= current_user }
if #album.save
redirect_to album_path(#album)
else
render :new
end
end
def edit
end
def update
#album.user_id = current_user.id
#album.avatar.purge # or album.avatar.purge_later
#album.avatar.attach(params[:avatar])
if #album.update(album_params)
redirect_to album_path(#album), notice: "Your album has been updated."
else
render 'edit'
end
end
def destroy
#album.destroy #destroy is for associated objects
#album.avatar.purge
redirect_to albums_path
end
private
def set_current_user
#user = current_user
end
def set_album
#album = Album.exists?(params[:id]) ? Album.find(params[:id]) : nil
redirect_to not_found_path if #album.nil?
end
def album_params
params.require(:album).permit(:artist, :title, :avatar, :user_id, reviews_attributes:[:title, :date, :content])
end
end
You can use a rescue block at the top of your ReviewsController like this:
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
Then, at the bottom of your file, you can create your record_not_found method:
private
def record_not_found
render file: "#{Rails.root}/public/404", layout: true, status: :not_found
end
The render file: in this case is going to the public directory and displaying the 404.html view.
Related
I'm at the end of a nested resource Rails app but I can't seem to figure out how to delete a review. I can delete an album just fine. My reviews belong to albums. Users have both albums and reviews.
I would also like to be able to make sure Users cannot delete reviews that they didn't write. I think that is where my error is coming from.
I keep getting this error:
ActiveRecord::RecordNotFound in AlbumsController#destroy
Couldn't find Album with 'id'=17
Extracted source (around line #57):
55
56
57
58
59
60
def set_album
#album = Album.find(params[:id])
end
def album_params
Here is my reviews controller:
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :delete, :edit, :update]
before_action :set_current_user, only: [:index, :new, :edit, :delete]
before_action :find_album, only: [:create, :edit]
before_action :must_login, only: [:index, :new, :create, :edit, :update, :delete]
def index
#albums = Album.with_recent_reviews
end
def show
##reviews = Review.where("album_id = ?", params[:album_id])
end
def new
if params[:album_id] && #album = Album.find_by(id: params[:client_id])
#review = #album.reviews.build
else
redirect_to albums_path
end
end
def create
#review = current_user.reviews.build(review_params)
#review.album = #album
if #review.save
redirect_to album_path(#album)
else
#album = #review.album
render :new
end
end
def edit
end
def update
if #review.update(review_params)
redirect_to album_path(params[:album_id])
else
render 'edit'
end
end
def destroy
if current_user.id == #review.user_id
#review.destroy
redirect_to album_path(params[:album_id])
else
flash[:error] = "Unable to delete your review. Please try again."
redirect_to album_reviews_path(#review)
##review.destroy
end
end
private
def set_review
#review = Review.find(params[:id])
end
def set_current_user
#user = current_user
end
def find_album
#album = Album.find(params[:album_id])
end
def review_params
params.require(:review).permit(:title, :date, :content, :user_id, :album_id, album_attributes:[:artist, :title, :user_id])
end
end
Here is my reviews index form where the delete link is located:
<% #albums.each do |album| %>
<br>
<br>
<% if album.avatar&.attached? %>
<image src="<%=(url_for(album.avatar))%>%" style="width:350px;height:350px;">
<% end %>
<br>
<%= album.artist %> - <%= album.title %>
<br>
<%= link_to "View Album", album_path(album) %>
<%= link_to "Edit Album", edit_album_path(album) %>
<br><br>
<% album.reviews.each do |review| %>
<% unless review.id.nil? %>
<small>Date written: <%= review.date %></small><br>
<small>Written by: <%= review.user.name %></small><br>
<strong>Title: <%= review.title %></strong><br>
Review: <%= review.content %><br>
<%= link_to "Edit Review", edit_album_review_path(album_id: album.id, id: review.id) %>
<%= link_to 'Delete', album_path(album_id: album.id, id: review.id), method: :delete, data: { confirm: 'Are you sure?' } %>
<br><br>
<% end %>
<% end %>
<br>
<% end %>
Albums controller:
class AlbumsController < ApplicationController
before_action :set_album, only: [:show, :edit, :update, :destroy]
before_action :must_login, only: [:new, :show, :create, :edit, :update, :destroy]
def index
#albums = Album.all
#user = current_user
end
def show
#review = #album.reviews.build
#review.user = current_user
# If you want to have some flag to indicate its status
##review.draft = true
#review.save
#reviews = Review.recent #scope
end
def new
#album = Album.new
#user = current_user
end
def create
#user = User.find(current_user.id)
#album = current_user.albums.build(album_params)
#album.user_id = current_user.id
if #album.save
redirect_to album_path(#album)
else
render :new
end
end
def edit
#user = current_user
end
def update
##album = current_user.albums.build(album_params)
#album.user_id = current_user.id
if #album.update(album_params)
redirect_to album_path(#album), notice: "Your album has been updated."
else
render 'edit'
end
end
def destroy
#album.delete
redirect_to albums_path
end
private
def set_album
#album = Album.find(params[:id])
end
def album_params
params.require(:album).permit(:artist, :title, :avatar, :user_id, review_attributes:[:title, :date, :content, :user_id, :album_id])
end
end
You have this issue because you are not passing an album_id to the destroy action of the review controller. The reason you need an album_id is because your routes probably look like this (since you said they were nested):
http://localhost:3000/albums/1/reviews
You can see in your route that you need an album_id (the 1 after the album). Try changing your review destroy action to this:
def destroy
if current_user.id == #review.user_id
#album.reviews.find(params[:id]).destroy
redirect_to album_path(params[:album_id])
else
flash[:error] = "Unable to delete your review. Please try again."
redirect_to album_reviews_path(#review)
end
end
You'll also have to change your before_action in the review controller to this, since you need the album_id to destroy the review:
before_action :find_album, only: [:create, :update, :destroy]
I am using devise and my destroy link path is not working on my rails app and I am not sure why :/ When I click on it, it is invoking the 'show' method. I have spent some time looking over the problem.
I believe the problem to be in my index.html.erb file. Have a look :) I understand the word 'pin' should not follow the link to 'destroy' as that is invoking the show method, but I don't know what else to put there instead.
Index.html.erb:
<div id="pins">
<% #pins.each do |pin| %>
<div class="box">
<%= image_tag pin.image.url %>
<%= pin.description %>
<%= pin.user.email if pin.user %>
<%= link_to 'Show', pin %>
<% if pin.user == current_user %>
<%= link_to 'Edit', edit_pin_path(pin) %>
<%= link_to 'Destroy', pin, method: :delete, data: { confirm: 'Are you sure more than anything!?' } %></td>
<% end %>
</div>
<% end %>
</div>
Pins_controller.rb:
class PinsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :set_pin, only: [:show, :edit, :update, :destroy]
def index
#pins = Pin.all
end
def show
#pin = Pin.find params[:id]
end
def new
#pin = Pin.new
end
def edit
end
def create
#pin = Pin.new(pin_params)
if #pin.save
redirect_to #pin, notice: 'Pin was successfully created.'
else
render action: 'new'
end
end
def update
if #pin.update(pin_params)
redirect_to #pin, notice: 'Pin was successfully updated.'
else
render action: 'edit'
end
end
def destroy
#pin.destroy
redirect_to pins_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find(params[:id])
end
def correct_user
#pin = current_user.pins.find(params[:id])
redirect_to pins_path, notice: "Not allowed!" if #pin.nil?
end
# Never trust parameters from the scary internet, only allow the white list through.
def pin_params
params.require(:pin).permit(:description, :image)
end
end
And my routes.rb file
Rails.application.routes.draw do
resources :pins
devise_for :users
root "pages#home"
get "about" => "pages#about"
end
My problem was that I did not list 'jquery' in my application.js
Inserting that solved my problem.
I am trying to fetch booking controller's new form, from the cab index page. how can i fetch it? how can access the new form from cab index page where i have shown all the cabs which are added..
cab controller
class CabsController < ApplicationController
before_action :find_cab, only: [:show, :edit, :update, :destroy]
def index
#cabs = Cab.all.order("created_at DESC")
end
def new
#cab = Cab.new
end
def show
#reviews = Review.where(cab_id: #cab.id).order("created_at DESC")
if #reviews.blank?
#avg_review=0
else
#avg_review=#reviews.average(:rating).round(2)
end
end
def edit
end
def create
#cab = Cab.new(cab_params)
if #cab.save
redirect_to #cab
else
render 'new'
end
end
def update
if #cab.update(cab_params)
redirect_to #cab
else
render 'edit'
end
end
def destroy
#cab.destroy
redirect_to root_path
end
private
def find_cab
#cab = Cab.find(params[:id])
end
def cab_params
params.require(:cab).permit(:name, :number_plate, :seat, :image)
end
end
booking controller
class BookingsController < ApplicationController
before_action :find_booking, only: [:show, :edit, :update, :destroy]
before_action :find_cab
def index
#bookings = Booking.where(cab_id: #cab.id).order("created_at DESC")
end
def new
#booking = Booking.new
end
def show
end
def edit
end
def create
#booking = Booking.new(booking_params)
#booking.user_id = current_user.id
#booking.cab_id = #cab.id
if #booking.save
redirect_to cab_booking_path(#cab, #booking)
else
render 'new'
end
end
def update
end
def destroy
end
private
def find_booking
#booking = Booking.find(params[:id])
end
def find_cab
#cab = Cab.find(params[:cab_id])
end
def booking_params
params.require(:booking).permit(:date, :address, :start_destination, :destination, :start_date, :end_date, :contact_no)
end
end
routes
resources :cabs do
resources :bookings
end
cab/index.html.erb
<div class="container">
<h2>All Cabs</h2>
<div class="row">
<% #cabs.each do |cab| %>
<div class="col-sm-6 col-md-3">
<div class="thumbnail">
<%= link_to image_tag(cab.image.url(:medium), class: 'image'), cab %><br>
Cab Name : <h4><%= cab.name %></h4>
<%= link_to "Book Now", new_cab_booking_path(#cab, #booking) %> # i wanted to create this link
</div>
</div>
<% end %>
</div>
<%= link_to "Add Cab", new_cab_path, class: 'btn btn-default' %>
the error i am getting is
No route matches {:action=>"new", :cab_id=>nil, :controller=>"bookings"} missing required keys: [:cab_id]
No route matches {:action=>"new", :cab_id=>nil,
:controller=>"bookings"} missing required keys: [:cab_id]
The problem is with this line
<%= link_to "Book Now", new_cab_booking_path(#cab, #booking) %>
which should be
<%= link_to "Book Now", new_cab_booking_path(cab) %>
Newbie again in Rails. Following Michael Hartl's tutorial on rails and I'm trying to pass the last section and I get this error
undefined method `id' for #<String:0x3794b80>
It comes from my _feed_item.html.erb and I don't understand why I'm getting this error.
<li id="<%= feed_item.id %>">
<%= link_to gravatar_for(feed_item.user), feed_item.user %>
<span class="user">
<%= link_to feed_item.user.name, feed_item.user %>
</span>
<span class="content"><%= feed_item.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(feed_item.created_at) %> ago.
</span>
<% if current_user?(feed_item.user) %>
<%= link_to "delete", feed_item, method: :delete, data: { confirm: "You sure?" }, title: feed_item.content %>
<% end %>
</li>
Hey guys, sorry I feel; asleep after.
When reviewing all my controllers I don't particularly see where it was defined however it did work before I started the last task so I don't know what happened in between.
Here is the user_controller
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
def new
#user=User.new
end
def create
#user=User.new(params[:user])
if #user.save
#Handle a save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def show
#user=User.find(params[:id])
#microposts=#user.microposts.paginate(page: params[:page])
end
def edit
#user=User.find(params[:id])
end
def update
#user=User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success]="Successfully updated your profile"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
def correct_user
#user=User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
def index
#users=User.paginate(page: params[:page])
end
def destroy
User.find(params[:id]).destroy
flash[:success]="User destroyed"
redirect_to users_url
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
def following
#title="Following"
#user=User.find(params[:id])
#users=#user.followed_users.paginate(page: params[:page])
render 'show_follow'
end
def followers
#title="Followers"
#user=User.find(params[:id])
#users=#user.followers.paginate(page: params[:page])
render 'show_follow'
end
end
micrpost_controller
class MicrpostsController< ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
def index
end
def create
#micropost=current_user.microposts.build(params[:micropost])
if #micropost.save
flash[:success]="Micropost Created!"
redirect_to root_url
else
#feed_items = []
render 'static_pages/home'
end
end
def destroy
#micropost.destroy
redirect_to root_url
end
def correct_user
#micropost=current_user.microposts.find_by_id(params[:id])
redirect_to root_url if #micropost.nil?
end
end
I got it to work people. The issues was in my micropost model.
def self.from_users_followed_by(user)
followed_user_ids= "SELECT followed_id FROM relationships WHERE follower_id=:user_id",
where("user_id IN (#{followed_user_ids}) OR user_id=:user_id", user_id: user)
end
should have been
def self.from_users_followed_by(user)
followed_user_ids= "SELECT followed_id FROM relationships WHERE follower_id=:user_id"
where("user_id IN (#{followed_user_ids}) OR user_id=:user_id", user_id: user.id)
end
This is my first ror app.
I have main page: home.html.erb
I have form there.
<%= form_for(#lead ,:html => {:class => 'check_form'}) do |f| %>
<%= f.text_field :phone, placeholder: 'phone' %>
<%= f.submit "Check car status", class: "btn btn-large btn-primary" %>
<% end %>
Backstory: a customer(I call him Lead can input his phone number and check status of his car which is being repaired now.)
Right now this view home.html.erbis served by static_pages_controller
class StaticPagesController < ApplicationController
def home
end
def help
end
def about
end
def contact
end
end
I have also LeadsController
class LeadsController < ApplicationController
#before_action :signed_in_user, only: [:index, :edit, :update]
#before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: [:index, :edit, :update, :destroy]
def index
#leads = Lead.paginate(page: params[:page])
end
def destroy
Lead.find(params[:id]).destroy
flash[:success] = "record deleted."
redirect_to leads_url
end
def show
#lead = Lead.find(params[:id])
end
def new
#lead = Lead.new
end
def create
#lead = Lead.new(lead_params)
if #lead.save
#sign_in #lead
flash[:success] = "Request successfully created!"
redirect_to #lead
else
render 'new'
end
end
def edit
#lead = Lead.find(params[:id])
end
def update
#lead = Lead.find(params[:id])
if #lead.update_attributes(status: params[:status])
flash[:success] = "Information updated"
redirect_to leads_url
else
render 'edit'
end
end
private
def lead_params
params.require(:lead).permit(:name, :email, :phone, :car_type,
:car_year, :car_manufacturer, :car_model, :photo1, :photo2, :coords )
end
# Before filters
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
def correct_user
#lead = Lead.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
What I want to do when user inputs his phone number to find lead in database with the same phone number and show repair status to user.
But it generates an error:
First argument in form cannot contain nil or be empty
So I got that form_for(#lead.. here #lead is empty.
But what should I do to get rid of this error.?
First argument in form cannot contain nil or be empty
As your view(home.html.erb) is served by static_pages#home, you should initialize #lead in the static_pages#home action
def home
#lead = Lead.new
end