How to delete nested record - ruby-on-rails

My girl model has comments with using gem 'acts_as_commentable'
When I access example.com/girls/show/1
It shows ID#1 girl's profile.
All the posted comments are shown in the bottom of this page.
For each comment row, I want to add delete button to delete a comment.
If it should pass the parameter to girls_controller.rb's comment_destroy action.
How action part and view should be??
It keeps undefined local variable or method `girls' error with codes below.
"girls/show.html.erb" view should be something like this. Just a part.
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>Body</th>
<th>Subject</th>
<th>Delete</th>
</tr>
<% #all_comments.each do |comment| %>
<tr>
<td><%= comment.id %></td>
<td><%= comment.title %></td>
<td><%= comment.body %></td>
<td><%= comment.subject %></td>
<td><%= button_to 'comment_destroy', girls, confirm: 'Are you sure?', :disable_with => 'deleting...', method: :delete %></td>
</tr>
<% end %>
</table>
girls_controller.rb's comment_destroy action should be something like this
def comment_destroy
#comment = comment.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to girls_url }
format.json { head :ok }
end
redirect_to :controller => 'girls', :action => 'show', :id => params[:girls][:id]
flash[:notice] = "comment deleted!"
end

It looks like you have comments nested under a girl, and you want to delete the comment.
Routes
resources :girls do
resources :comments, only: [:create, :destroy]
end
Then, you have a comments controller that handles your creation and destroy.
<%= button_to 'comment_destroy', [#girl, comment], confirm: 'Are you sure?', :disable_with => 'deleting...', method: :delete %>
The destroy method in your comments controller:
def destroy
#girl = Girl.find(params[:girl_id])
#comment = #girl.comments.find(params[:id])
if #comment.destroy
redirect_to #girl, notice: "Comment Removed"
else
redirect_to #girl, error: "We could not remove the comment"
end
end
end
UPDATE -- based on user's request to use a non-restful solution
Routes:
resources :girls do
member do
delete :delete_comment, to: "girls#delete_comment", as: "delete_comment"
end
end
controller
def delete_comment
#girl = Girl.find(params[:id])
#comment = #girl.comments.find(params[:comment_id])
if #comment.destroy
redirect_to #girl, notice: "Comment Removed"
else
redirect_to #girl, error: "We could not remove the comment"
end
end
View link
<%= button_to 'comment_destroy', delete_comment_path(#girl, comment_id: comment.id), confirm: 'Are you sure?', :disable_with => 'deleting...', method: :delete %>
Final note: I really don't like this solution. You should have a Comments controller and go with my first solution.

Related

Passing comments_id to controller in Rails app

I am unable to edit/delete comments in a basic Rails MVC, but the trouble I'm having is that the comments_controller looks for the user_id and not the comments_id, because the user_id is the foreign key. My assumption was that Comment.find(params[:id]) would lead to comments_id, but this is npot the case.
This is the last part of my comments_controller:
def edit
#comment = Comment.find(params[:id])
#user = current_user
end
def update
#comment = Comment.find(params[:id])
#user = current_user
#comment.update(comment_params)
redirect_to #comment
end
def destroy
#user = current_user
#comment = Comment.find(params[:id])
#comment.destroy
redirect_to comments_path
end
private
def comment_params
params.require(:comment).permit(:user_id, :location, :title, :body)
end
The comments in the views that I'm trying to edit/delete look like this:
<% #user.comments.each do |w| %>
<tr>
<td>Location:<%= w.location %></td>
<td>Title:<%= w.title %></td>
<td>Body:<%= w.body %></td>
<td><%= link_to 'Edit', edit_comment_path %></td>
<td><%= link_to 'Destroy', comment_path,
method: :delete,
data: { confirm: 'Are you sure?' } %></td><br>
</tr>
<% end %>
Thanks for any advice offered :-)
When you edit/destroy your comment, you need to pass the actual comment in the link_to helper. Something like link_to 'Destroy', w, method: :delete, data: { confirm: 'Are you sure?' } will do.
Similarly with edit: link_to 'Edit', edit_comment_path(w)

Delete post redirect to the post

I'm currently trying to delete a post through the link
<%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' }
The problem is that when i click on it, instead of destroying the post, it's redirect me to the show view of the post.
Here is my index.html.erb
<table>
<tr>
<th>titre</th>
<th>description</th>
</tr>
<% #posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.description %></td>
<td><%= link_to 'Show', post_path(post)%> </td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<br>
And here is my controller posts.controller
class PostsController < ApplicationController
before_action :set_post, except: [:create, :index, :new]
def index
#posts = Post.all
end
def show
end
def new
#post = Post.new
end
def edit
end
def create
#post = Post.new(post_params)
#post.save
redirect_to :action => "index"
end
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Lime was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
#post.destroy
redirect_to root_path, :notice => "Vous n'ĂȘtes plus un batard"
end
private #private has nos end
#Must be set to update later
def set_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :description)
end
end
Thx for helping
Make sure you have //= require jquery and //= require jquery_ujs included in your application.js And include application.js included into view/layout/application.html.erb

Rails "No route matches POST /images/1" error

I looked through several other similar help questions, and I'm not seeing my error. I have destroy, new, create all working, but post and show throw errors. Also oddly enough, clicking the 'edit' button on the index view throws an error, but going directly to http://localhost:3000/images/1 gives me the 'show' page (no idea why it isn't giving an edit page).
relevant files:
images_controller.rb
class ImagesController < ApplicationController
def index
#images = Image.all
end
def new
#image = Image.new
end
def create
#image = Image.new(image_params)
if #image.save
redirect_to images_path, notice: "Your image #{#image.name} has been uploaded."
else
render "new"
end
end
def edit
#image = Image.find(params[:id])
end
def destroy
#image = Image.find(params[:id])
#image.destroy
redirect_to images_path, notice: "The image #{#image.name} has been removed from the database."
end
def show
#image = Image.find(params[:id])
end
private
def image_params
params.require(:image).permit(:name, :attachment)
end
end
routes.rb
Rails.application.routes.draw do
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
resources :images#, only: [:index, :new, :create, :update, :edit, :show, :destroy]
root "images#index"
end
Note: I have also added the lines
get 'images/edit'
get 'images/details'
But to no avail.
index.html.erb:
<% if !flash[:notice].blank? %>
<div class="alert alert-info">
<%= flash[:notice] %>
</div>
<% end %>
<br />
<%= link_to "New Image", new_image_path, class: "btn btn-primary" %>
<br />
<br />
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>View Link</th>
<th> </th>
</tr>
</thead>
<tbody>
<% #images.each do |image| %>
<tr>
<td><%= image.name %></td>
<td><%= link_to "#{image.name}", image.attachment_url %></td>
<td><%= button_to "Edit", image, method: :edit, class: "btn btn-primary", confirm: "edit #{image.name}?" %></td>
<td><%= button_to "Show", image, method: :show, class: "btn btn-primary"%></td>
<td><%= button_to "Delete", image, method: :delete, class: "btn btn-danger", confirm: "Are you sure that you wish to delete #{image.name}?" %></td>
</tr>
<% end %>
</tbody>
</table>
I suppose there are no HTTP methods like this:
method: :edit, method: :show
Try to do smth like this:
link_to "Edit", edit_image_path(image)
link_to "Show", image_path(image)
And remove this line from routes.rb
get 'images/edit'
resources has already created rout to edit action for you. You can see it http://localhost:3000/rails/info/routes
button_to by default will make post request you need link_to "edit" to make get request. when you type in your browser http://localhost:3000/images/1 you are making get request so it works.
link_to "Edit", edit_image_path image
check these links for link_to and button_to
http://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to
http://apidock.com/rails/ActionView/Helpers/UrlHelper/button_to

Ruby on Rails retrieve and display data according to user, e.g. retrieve all reviews created by one user

In my Ruby on Rails application users are able to leave reviews for products, and then the administrator can view all reviews. What I want to be able to do is make it so that an administrator can still see all reviews left by everyone but a normal user can only view their own reviews and not everyone elses. Is there a simple way I can do this without using java?
Below is my index.html.erb that displays all reviews by everyone.
<div class="centre-content">
<div class="main-title">All reviews:</div>
<table>
<tr>
<th>Product</th>
<th>Name</th>
<th>Review text</th>
<th>No of stars</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #reviews.each do |review| %>
<tr>
<td><%= review.product.title %></td>
<td><%= review.user.name %></td>
<td><%= review.review_text.truncate(35) %></td>
<td><%= review.no_of_stars %></td>
<td><%= link_to 'Show', review %></td>
<td><%= link_to 'Edit', edit_review_path(review) %></td>
<td><%= link_to 'Destroy', review, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'Back', :back %>
</div>
application.html.erb where the administrator can click to view all reviews:
<% if admin? %>
<li> <%= link_to "Users", "" , :class => active_menu("users") %>
<ul>
<li> <%= link_to "Users" , users_path %> </li>
<li> <%= link_to "Edit profile" , edit_user_path(session[:user_id]) %> </li>
</ul>
<li> <%= link_to "Categories", categories_path , :class => active_menu("categories") %>
<li> <%= link_to "Reviews", reviews_path , :class => active_menu("reviews") %>
<% end %>
reviews_controller.rb:
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :edit, :update, :destroy]
# GET /reviews
# GET /reviews.json
def index
#reviews = Review.all
end
# GET /reviews/1
# GET /reviews/1.json
def show
end
def new
if logged_in?
existing_review = Review.find_by_user_id_and_product_id(session[:user_id], params[:id])
if existing_review == nil
#review = Review.new(product_id: params[:id],
user_id: User.find(session[:user_id]).id)
session[:return_to] = nil
else
redirect_to edit_review_path(existing_review.id)
end
else
session[:return_to] = request.url
redirect_to login_path, alert: "You need to login to write a review"
end
end
# GET /reviews/1/edit
def edit
end
def create
#review = Review.new(review_params)
if #review.save
product = Product.find(#review.product.id)
redirect_to product, notice: 'Your review was successfully added.'
else
render action: 'new'
end
end
# PATCH/PUT /reviews/1
# PATCH/PUT /reviews/1.json
def update
respond_to do |format|
if #review.update(review_params)
format.html { redirect_to #review, notice: 'Review was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #review.errors, status: :unprocessable_entity }
end
end
end
# DELETE /reviews/1
# DELETE /reviews/1.json
def destroy
#review.destroy
respond_to do |format|
format.html { redirect_to reviews_url }
format.json { head :no_content }
end
end
def displays
product = Product.find(params[:id])
#reviews = product.reviews
if #reviews.empty?
redirect_to product, notice: "No reviews - as yet ..."
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_review
#review = Review.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def review_params
params.require(:review).permit(:product_id, :user_id, :review_text, :no_of_stars)
end
end
reviews.rb model:
class Review < ActiveRecord::Base
belongs_to :product
belongs_to :user
validates :review_text, :presence => { :message => "Review text: cannot be blank ..."}
validates :review_text, :length => {:maximum => 2000, :message => "Review text: maximum length 2000 characters"}
validates :no_of_stars, :presence => { :message => "Stars: please rate this book ..."}
end
Is there anyway I can make it so that a user only views their own reviews?
In your controller display method, you can do stg like this i think :
def display
product = Product.find(params[:id])
#reviews = product.reviews.select! { |s| s.user_id == current_user.id } unless admin?
....
end
That way, only admin will have all reviews, and others users will only see their own reviews (with theirs ids)
you dont have current_user method but it es explained well in this tutorial :
https://www.railstutorial.org/book/log_in_log_out#sec-current_user
it is the same as session[:id] but in a well ordered manner.
Ps: i'm not sur about the s.user_id ... don't remember the exact syntax but should be it.
Another way :
you could take the reviews for this specific product id and then filter out by the user id.
`#reviews = Reviews.find_by_product_id(params[:product_id]).select { |r| r.user_id == current_user.id }`

undefined method `destroy' for nil:NilClass can't find the id of my data

I have a table that users can add data to, I've also included a button for users to delete a row of data:
<tbody>
<% #jobs.each do |job| %>
<tr>
<td><%= link_to job.job_title, job.url, :target => "_blank" %></td>
<td><%= job.company %></td>
<td><%= job.location %></td>
<td><%= link_to "", list_url(job), method: :delete, class: "fa fa-trash-o" %></td>
</tr>
<% end %>
</tbody>
However when the delete button is pressed I get a "undefined method `destroy' for nil:NilClass" error. In my server logs it says that the ID is null and I can't seem to grab the id of that particular row of data.
I've looked at other similar Stackoverflow questions to the one I am asking but the solutions found there haven't worked for me.
For reference here are my routes that relate to adding, showing and deleting data:
get '/jobs' => 'search#list', as: 'list'
post '/jobs' => 'search#create'
delete '/jobs' => 'search#destroy'
And my controller:
def new
#job = Job.new
end
def create
#job = Job.new(job_params)
if #job.save
redirect_to list_url, notice: "You've successfully added the job to the list"
else
render 'search', notice: "Something went wrong, please try again"
end
end
def list
#jobs = Job.all
#job = Job.find_by_id(params[:id])
end
def destroy
#job = Job.find_by_id(params[:id])
#job.destroy
redirect_to list_url, notice: "Job destroyed"
end
def job_params
params.require(:job).permit(:job_title, :company, :location, :url)
end
In your delete link, you want to link to the object itself, not the URL to the object. So change
<td><%= link_to "", list_url(job), method: :delete, class: "fa fa-trash-o" %></td>
to
<td><%= link_to "", job, method: :delete, class: "fa fa-trash-o" %></td>
On top of that, you'll need the appropriate CRUD routes defined, so I would recommend the following in your routes.rb file:
resources :jobs, controller: 'search'
Don't think you want to link to list_url if you're trying to specify a particular instance of job. Maybe something like
<td><%= link_to "", job_path(job), method: :delete, class: "fa fa-trash-o" %></td>

Resources