I am building a mock up of reddit. When on my show view that displays the link & title I submit I have included an option(link) to destroy the submission.
When I click on the destroy I get:
ActionController::ParameterMissing in LinksController#destroy
param not found: link
on line:
params.require(:link).permit(:url, :title)
This is my full Links controller:
class LinksController < ApplicationController
def index
#link = Link.all
end
def show
#link = Link.find(params[:id])
end
def new
#link = Link.new
end
def create
#link = Link.new(link_params)
if #link.save
redirect_to #link
else
render action: 'new'
end
end
def destroy
#link = Link.find()
if #link.destroy
redirect_to index: 'action'
else
render show: 'action'
end
end
private
def link_params
params.require(:link).permit(:url, :title)
end
end
This is my show view:
<h1> This is the show view </h1>
<%= #link.title %>
<%= #link.url %>
<%= link_to 'Edit', edit_link_path(#link) %>\
<%= link_to 'Destroy', (#link), method: :delete, data: { confirm: 'Are you sure?' } %>
I'm really confused, have tried multiple things but can't get it to work. How can i fix this?
Looks like you permit is missing :id and your destroy is missing params[:id] in the find clause.
Your problem is:
def destroy
#link = Link.find()
...
You need something like:
def destroy
#link = Link.find(params[:id])
What's happening is that your Destroy link is sending a DELETE request to some URL like /link/23 with 23 being params[:id]. You need to find the appropriate Link object by using Link.find(params[id]) before you destroy it (similar to how you would in show).
Related
I am building an app for practice,(Instagram replica), and I am having a really hard time getting a feature to work.
What I want to happen is, a user is able to edit or delete their own comments about a picture. I was able to get the delete feature to work, but I am unable to figure out the 'Edit comment' feature. I want the user to be able to edit the comment from within the picture show page. Code is below.
pics_controller.rb
class PicsController < ApplicationController
before_action :find_pic, only: [:show, :edit, :update, :destroy, :upvote]
before_action :authenticate_user!, except: [:index, :show]
before_action :require_same_user, only: [:edit, :update, :destroy]
def index
#pics = Pic.all.order("created_at DESC")
end
def show
end
def new
#pic = current_user.pics.build
end
def create
#pic = current_user.pics.build(pic_params)
if #pic.save
redirect_to #pic, notice: "Your pic has been posted!"
else
render :new
end
end
def edit
end
def update
if #pic.update(pic_params)
redirect_to #pic, notice: "Awesome! Your Pic was updated!"
else
render :edit
end
end
def destroy
if #pic.destroy
redirect_to root_path
end
end
def upvote
#pic.upvote_by current_user
redirect_back fallback_location: root_path
end
private
def pic_params
params.require(:pic).permit(:title, :description, :image)
end
def find_pic
#pic = Pic.find(params[:id])
end
def require_same_user
if current_user != #pic.user
flash[:danger] = "You can only edit or delete your own pictures"
redirect_to root_path
end
end
end
comments_controller.rb
class CommentsController < ApplicationController
def create
#pic = Pic.find(params[:pic_id])
#comment = #pic.comments.create(params[:comment].permit(:name, :body))
redirect_to pic_path(#pic)
end
def edit
#pic = Pic.find(params[:pic_id])
#comment = #pic.comments.find(params[:id])
redirect_to #pic
end
def update
#comment = #pic.comments.find(params[:id])
#comment.update_attributes(comment_params)
if #comment.save
redirect_to #pic
end
end
def destroy
#pic = Pic.find(params[:pic_id])
#comment = #pic.comments.find(params[:id])
#comment.destroy
redirect_to pic_path(#pic)
end
def show
#pic = Pic.find(params[:pic_id])
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
And here is the (_comment.html.erb) partial being called from the show page
<div class="card" style="width: 18rem;">
<div class="card-header">
<span class="badge badge-dark"><%= comment.name %></span>
</div>
<ul class="list-group list-group-flush">
<p><%= comment.body %></p>
</ul>
</div>
<% if user_signed_in? && comment[:body].present? %>
<p><%= link_to 'Delete Comment', [comment.pic, comment], method: :delete, class: "btn btn-danger",
data: { confirm: "Are you sure?" } %></p>
<p><%= link_to 'Edit Comment', edit_pic_comment_url(#pic, comment), class: 'btn btn-primary' %></p>
<% end %>
Any help is greatly appreciated. TIA
You need to ajaxify for that scenario. The steps will be:
Create the edit link with data-remote=true option. It'll enable the link to hit on the server with a ajax request. Also, add a editable div.
Edit
<div id="comment_#{comment.id}_form"></div>
In the edit method respond the request using js. Like:
def edit
respond_to do |format|
format.js # actually means: if the client ask for js -> return edit.js
end
end
Create edit.js file. In there, render the comment _form.html.erb on the defined div with ID - comment_4_form (Lets assume you're now editing comment with id 4).
It's not elaborated I know. The solution will be much bigger if I elaborate. But you are good to go if you understand the cycle.
I'm running into a problem that I'm not exactly sure how to fix.
I have a simple to do list application with AJAX functionality on methods such as 'new', 'create', 'complete', 'delete', as well as Devise authentication.
When I first enter a new session with a User, all of these methods work without a problem. Additionally, the tasks are saved to only the user account, which is perfect.
However, when I log out of an account, and then log back in, the delete method no longer works. I receive the following error:
ActiveRecord::RecordNotFound (Couldn't find Task with 'id'=)
My tasks_controller.rb is below:
class TasksController < ApplicationController
def index
#task = current_user.tasks.all
end
def new
#task = Task.new
respond_to do |format|
format.js
format.html
end
end
def create
#task = current_user.tasks.new(task_params)
#task.save
respond_to do |format|
format.html
format.js
end
end
def update
#task = current_user.tasks.find(params[:id])
#task.toggle :complete
#task.save
respond_to do |format|
format.html
format.js
end
end
def destroy
#task = Task.find(params[:id])
#task.destroy
respond_to do |format|
format.js
format.html
end
end
private
def task_params
params.require(:task).permit(:id, :title, :complete)
end
end
I'm not exactly sure how to fix this problem. Would anyone have an idea on what is going wrong here?
EDIT:
I noticed that on my index page, I have a link to destroy the user's session at the top:
<%= link_to "Log Out", destroy_user_session_path, :method => :delete %>
I'm wondering if rails is having some trouble with this as both the logout link and the delete link are referencing the same method. If so, how can I change the name of the delete method for Task?
<div class="delete"><%= link_to "X", task_path(#task), method: :delete, remote: true %></div>
What is #task referencing? It looks to me like you've set #task to a collection #task = current_user.tasks.all.
Which would be why your delete method can't find a specific record to delete.
-EDIT-
Change #task in your index controller to #tasks as it is a collection.
In your view, do something like:
<% #tasks.each do |task| %>
<div><%= task.title %><div class="delete"><%= link_to "X", task_path(task), method: :delete, remote: true %></div></div>
<% end %>
The key here is that you have task_path(task) which is referencing a specific task id as opposed to task_path(#task) which is referencing a collection of tasks.
Fairly new to rails and can't seem to get this simple destroy action working. All it does is redirect to the mod panel index page and doesn't destroy the record. Do I need to call .destroy in the destroy method? or is there something I'm missing?
mod_approval controller
def index
#guide = Guide.friendly.find(params[:guide_id])
#check_category = CheckCategory.where(guide_id: #guide.id).all
#category = Guide.friendly.find(#guide.id).categories.new
end
def destroy
redirect_to guide_mod_panel_mod_approval_index_path(#guide)
end
config/routes.rb
match '/guides/:guide_id/mod-panel/approve/reject' => 'mod_approval#destroy', :via => :delete, as: :guide_mod_panel_approve_destroy
index.html.erb
<% #check_category.each do |category| %>
<%= link_to "Reject", guide_mod_panel_approve_destroy_path(#guide, category), method: :delete, data: {confirm: "You sure?"} %><br>
<% end %>
You need to fetch the record from the database, then you can call destroy on the object, you can do this
def destroy
guide = Guide.find(params[:guide_id])
category = guide.categories.find(params[:id])
category.destroy
redirect_to guide_mod_panel_mod_approval_index_path(guide)
end
Hope that helps!
You should have to destroy object before:
def destroy
#destroyed_object.destroy # or Model.destroy(params[:id])
redirect_to guide_mod_panel_mod_approval_index_path(#guide)
end
EDIT: I managed to delete! i had to define teh instance variable #movies = Movie.find(params[:id]) to the delete method in the controller.
I still can't update though. I get "param is missing or the value is empty: movie"
I forgot to add my contrller! sorry!
I'm trying to replicate one of my in class exercises into another app, for practice.
The idea is to be able to add new movies into a database, and get the option to update their info, and delete them as well. I can add new content, but I can't update them or delete them.
Appreciate any inputs I can get.
Routes.rb
Rails.application.routes.draw do
root "movies#index"
get "/movies", to: "movies#index"
get "/movies/new", to: "movies#new", as: "new_movie"
get '/movies/:id', to: "movies#movie_page", as: "movie_page"
post "/movies", to: "movies#add"
get "/movies/:id/edit", to: "movies#edit", as: "movie_edit"
put "/movies/:id", to: "movies#update"
patch "/movies/:id", to: "movies#update", as: "update_movie"
delete "/movies/:id", to: "movies#delete", as: "delete_movie"
end
Controller
class MoviesController < ApplicationController
def index
#movies = Movie.all
end
def movie_page
#movies = Movie.find(params[:id])
end
def new
#movies = Movie.new
end
def add
#movies = Movie.create(movie_params)
redirect_to movies_path
end
def edit
#movies = Movie.find(params[:id])
end
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def delete
#movies = Movie.find(params[:id])
#movies.destroy
# flash[:notice] = "Shirt was deleted."
redirect_to root_path, notice: "Shirt was deleted."
end
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
# def set_movie
# #movies = Movie.find(params[:id])
# end
end
Form partial
<%= form_for #movies do |m| %>
<p>
<%= m.label :title %><br>
<%= m.text_field :title %>
</p>
<p>
<%= m.label :description %><br>
<%= m.text_field :description %>
</p>
<p>
<%= m.label :year_released %><br>
<%= m.text_field :year_released %>
</p>
<p>
<%= m.submit %>
</p>
<% end %>
Movie page html (individual movies, labeled by IDs)**I can't update or Delete, no route matches Delete.
When I press Update - I get param is missing or the value is empty: movie
<h1><%= #movies.title %></h1>
<h2>Released on : <%= #movies.year_released %> </h2>
<p> <%= #movies.description %> </p>
<%= link_to "Update", movie_edit_path(#movies) %>
<%= link_to "Delete", movies_path, method: :delete %
Edit page *I cant access this link. the form is the problem
<h1>Edit <%= #movies.title %> Info </h1>
<%= render "form" %>
<%= link_to "Cancel Edit", movie_edit_path(#movies) %>
Many thanks guys
def update
#movie = Move.find(params[:id])
#movie.update(movie_params)
redirect_to movie_path(#movie)
end
on your routes. all you need is resources :movies
you are getting param is empty because you have to pass in the id of the movie to update.
The major issue is that you do not load the variable #movies from the DB before you use it.
def update
#movies.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
def update
#movies.find(params[:id])
#movie.update(movie_params)
redirect_to #movies, notice: "Shirt was updated."
end
Aside from that you have tons of duplication and quite a few idiosyncrasies.
Rails uses these naming conventions for actions:
index
show (not movie_page)
new
create (not add)
edit
update
destroy (not delete)
You should follow them unless you have a damn good reason not to.
class MoviesController < ApplicationController
# cuts the duplication
before_filter :set_movie, except: [:new, :index]
def index
#movies = Movie.all
end
# GET /movies/:id
def show
end
# GET /movies/new
def new
#movie = Movie.new
end
# POST /movies
def create
#movie = Movie.create(movie_params)
redirect_to movies_path
end
# GET /movies/edit
def edit
end
# PUT|PATCH /movies/:id
def update
#movie.update(movie_params)
redirect_to #movie, notice: "Shirt was updated."
end
# DELETE /movies/:id
def destroy
#movie.destroy
redirect_to action: :index
end
private
def movie_params
params.require(:movie).permit(:title, :description, :year_released)
end
def set_movie
# Use the singular form when naming a variable with a single record
# failure to do so may result in tarring and feathering
#movie = Movie.find(params[:id])
end
end
I am building presentation builder, and I don't know how to destroy the chosen presentation presented in the list when I click on the button Remove.
My controllers looks like that:
def create
if logged_in?
presentation = current_user.presentations.create data: params.to_yaml
redirect_to edit_presentation_path(presentation)
end
end
def edit
render action: :new
end
# def destroy
# current_presentation.destroy
# end
def show
render action: :new
end
def list
#presentations = current_user.presentations
end
def update
current_presentation.update_attributes(data: params.to_yaml)
end
def home
if logged_in?
#presentations = current_user.presentations
end
end
My list of created presentations looks like that:
<% #presentations.each do |p| %>
<a > <%= p.id %>
Show
<a class="action"> Remove </a>
</a>
<% end %>
My goal is: to write correct destroy method and create a link Remove that executes this method for a particular presentation.
<%= link_to "Delete", p, method: :delete %>
Something like that should do it.
More here http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html
<%= link_to "Delete", your_destroy_path(p), method: :delete %>