My destroy/delete link simply refreshes the post page and doesn't actually delete the record.
<span class="delete-button"><%= link_to 'Delete', post_path(#post), method: :delete, data: { confirm: 'Are you sure?' } %>
</span>
Controller
def destroy
#post= Post.find(params[:id])
#post.destroy
redirect_to posts_path
end
The solution was to use button_to instead of link_to
That revealed additional error that required me to define the has_many association above/before the has_many :through associations in the Post model.
Unsure why link_to does not work in this case.
You are failing to check if #post.destroy succeeds, it returns true or false.
Simplest thing to do is to use #post.destroy! which will throw an exception if it fails. In general, use the ! versions to ensure you don't miss any errors: create!, destroy!, save!, and update!.
My guess is the #post has associated objects which refer to the Post. These must be deleted before Post is deleted. You can fix this by adding dependent: :destroy to its relationships.
class Comment
belongs_to :post
end
class Post
has_many :comments, dependent: :destroy
end
If your page is refreshing and not performing a redirect per the controller action, it's possible that the page doesn't have rails-ujs set up. Without it you can't make non-GET requests via hyperlinks, so the link would simply go to the post's show page.
If the record is truly failing to delete, it could be due to several reasons. One way to narrow down why the Post failed to delete would be to rescue out of the exception that destroy! raises and log or display the post's errors:
def destroy
post = Post.find(params[:id])
post.destroy!
redirect_to posts_path, notice: "Post deleted successfully"
rescue ActiveRecord::RecordNotDestroyed => e
failure_message = "Post failed to delete: #{e.record.errors.full_messages}"
Rails.logger.warn "==> #{failure_message}"
redirect_to posts_path, alert: failure_message
end
If you don't have flash messages set up for your view, you can place this in your view file:
<% flash.each do |_type, message| %>
<div><%= message %></div>
<% end %>
Now if the post fails to delete you can display a flash message stating why it failed (or you can check your logs for a ==> Post failed to delete: ... line).
Related
I am trying to follow the following guide for starting Ruby on Rails. Everything went well until I try to destroy (delete comments).
I receive the following error:
The action 'show' could not be found for CommentsController
I will post my code below.
http://guides.rubyonrails.org/getting_started.html
comments_controller.rb
class CommentsController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.create(comment_params)
redirect_to article_path(#article)
end
def destroy
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
#comment.destroy
redirect_to article_path(#article)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
end
articles_controller
class ArticlesController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
def index
#articles = Article.all
end
def show
#article = Article.find(params[:id])
end
def new
#article = Article.new
end
def edit
#article = Article.find(params[:id])
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
routes.rb
Rails.application.routes.draw do
resources :articles do
resources :comments
end
root 'welcome#index'
end
article.rb
class Article < ActiveRecord::Base
has_many :comments, dependent: :destroy
validates :title, presence: true,
length: { minimum: 5}
end
comment.rb
class Comment < ActiveRecord::Base
belongs_to :article
end
articles/index.html.erb
<h1>Listing Articles</h1>
<%= link_to 'New article', new_article_path %>
<table>
<tr>
<th>Title</th>
<th>Text</th>
<th colspan="3"></th>
</tr>
<% #articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td><%= link_to 'Show', article_path(article) %></td>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article_path(article),
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
Just not sure what it can be. Please advise. I will supply more code if needed.
The answer will be in your routes.rb and in the URL you are trying to call.
The URL is probably /comment/123, and the routes.rb likely has something like get 'comment/:id' => 'comment#show' in it (or a resource statement for comments).
So rails tries to show the page for a comment and you did not implement the function. The error message is saying exactly what it needs to say (you do indeed not have a .show method in your CommentsController).
If my guesses were not correct, then please post your routes.rb and the URL you are requesting.
I've been working through the same tutorial, and just today ran into the exact same issue as the original poster.
I didn't notice exactly when it started, but it seemed to have started somewhere in section 6, 7 or 8 (adding comments to blog, refactoring, or adding deletion of comments).
Furthermore, clicking links within the app (i.e. the 'Back' link) would spawn a new tab. Likewise, when clicking the 'Destroy' link, the browser's confirmation dialog would appear over the current tab (correct behavior), but at the same time a new browser tab would appear (incorrect) - I think this new tab behavior (a type of 'show'ing of the comment that the user is in process of deciding whether to go ahead and destroy) is what was causing the error.
After finishing the tutorial (one more section, basic authentication), I quit & re-launched Chrome, and then also quit & restarted the server (ctrl-c, then bin/rails server).
After doing this, all is well. Both the spawning extra tab behavior, as well as the spurious show action being triggered (thus causing the error) - when the destroy confirmation sheet appears - have stopped.
So it seems that this problem was simply some spurious noise - perhaps caused by something that's changed (in the rails environment?) between the time the tutorial was originally written, and when the original poster ran into this behavior (and still persisting today, July '18, with rails 5.2).
I know this is old, but the tutorial "Getting Started with Rails" is still the top result on Google for those looking to start building web applications using Rails.
I encountered the same issue today and it kind of makes sense. If you want to delete a comment, you can't simply navigate to it with a GET request, you need to use a DELETE method.
I got around this by replacing link_to with button_to hoping that Rails would sort out the "magic" and it did.
Code used:
<%= button_to 'Destroy Comment', [comment.article, comment],
method: :delete,
data: { confirm: "Are you sure?" } %>
Instead of
<%= link_to 'Destroy Comment', [comment.article, comment],
method: :delete,
data: { confirm: "Are you sure?" } %>
You can add
def show
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
#comment.destroy
redirect_to article_path(#article)
end
to your comments_controller.rb
Actually these codes are identical to those in the def destroy
add in comment model belongs_to :user if you authenticate with user and other too whatever you belongs_to...
I have had some similar issues, for example:
The same message when trying to delete a comment:
The action 'show' could not be found for CommentsController
When trying to delete an article, it was not being deleted but rendering its page instead.
The confirmation dialog was not showing when deleting neither an article nor a comment.
I have tried to restart the server as well as one of the solutions above that says to create a show method identical to the destroy method. Well, it worked fine for deleting comments but it didn't seem right to me considering the RoR DRY pattern.
I ended up realizing that the browser's extension responsible for blocking JavaScript (NoScript 11.2.9) was active and causing those weird behaviors.
In this special case, it was not related with the Rails itself but external factors.
I have the same problem and I tried to add this to comments_controller.rb and it works
def show
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
#comment.destroy
redirect_to article_path(#article)
end
I ran into same problem but adding
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
worked for me rails 6 and webpack you should use this
Update: As I mentioned earlier you dont have show method in your CommentsController so you wont be able to visit the show page for any comment.
As you said you are trying to visit this url: localhost:3000/articles/2/comments/1 which is the show page for comment having id: 1 and the routes(resources :comments) is trying to take it to show action. Hence the error rightly thrown show could not be found for CommentsController.
Please remove the url from your browser and try visiting again the article show page. It will work.
In my Rails 4 app, I have a calendar and a post models: a calendar has_many posts and a post belong_to a calendar.
In Calendars#Show, I display all the posts that belong to this calendar.
In this very same view, I use the following link to update the approval custom attribute of a post:
<%= link_to post_path(:id => #post.id, "post[approval]" => "ok"), :method => :patch %>
Problem, once I click this link, I am taken to the Posts#Show view of this post.
What I would like instead, is to remain on the same Calendars#Show view.
I thought of implementing a redirect_to :back in my Posts#Update action in the controller, but this is not possible, since this would redirect me to the Posts#Edit view when I update a post from this very same Posts#Edit view.
So, I am looking for a solution to implement a redirect_to specifically for my link_to helper with remote: true from the Calendars#Show to the Calendars#Show.
Is that possible?
with remote: true
If you're using remote (your code snippet does not have it), you won't be redirected anyway:
<%= link_to post_path(:id => #post.id, "post[approval]" => "ok"), :method => :patch, remote :true %>
The remote: true functionality invokes ajax, which is an XML call (through JS) to your server. By virtue of the call being out of "scope" (IE not a standard "request"), it will not cause any changes to your current browser state, unless you trigger them yourself:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def update
#post = Post.find params[:id]
respond_to do |format|
if #post.update
format.json #-> fired only when json is datatype
format.js #-> invokes app/views/posts/update.js.erb
format.html { redirect_to #post } #-> only fires on http request
end
end
end
end
#app/views/posts/update.js.erb
## do what you want here
from the Calendars#Show to the Calendars#Show
If you want to refresh your page, you could use:
#app/views/posts/update.js.erb
window.location.reload(true);
--
To give you some more context, ajax stands for asynrhconous javascript and xml. This means that each of the requests you send with it are considered to be asynchronous -- or out of scope of the "normal" HTTP request.
Ajax requests are meant to be used to apply changes / updates to an already loaded page. A good example would be a chat system or something.
Your question of how to redirect after an Ajax response, although not wrong, is definitely against convention of how it's considered to work. If you wanted to create a redirect as you are attempting to, I would highly recommend using a standard HTTP request with some conditions in your action:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def update
#post = Post.find params[:id]
#post.update post_params
redirect_to posts_path if #post.approved.changed?
redirect_to root_path if ....
end
end
Since this is an AJAX request, in your Post controller you need to respond to js:
def update
# ...
respond_to do |format|
if #post.update(post_params)
format.js { head :ok } # see here no redirects
# ... other formats
else
# ...
end
end
end
Is there a way to give back an error if a particular model is deleted in Rails 3.x+? If it's deleted via the web, an error code is given back. If it's deleted via console then a message is given with the reason it can't be deleted.
You can use a before_destroy. The link is here. Returning false from this validation message prevents the destruction of the object.
Well, the way that I usually delete something is...
from the view:
<%= link_to "Delete Post", #post, method: :delete, data: { confirm: "You're sure you want to DELETE the post '#{#post.title}'?" } %>
then in the post controller:
def destroy
Post.find(params[:id]).destroy
flash[:success] = "Blog entry deleted!"
redirect_to posts_path
end
So, the method: :delete just gets to the destroy route of the controller. Then you do what you want, right?
So instead of .destroy after you find the model, you could do:
def destroy
#post = Post.find(params[:id])
flash[:notice] = "Blog entry can't be deleted..."
puts "#{#post.name} can't be deleted because..." #this line is what shows up in the console
redirect_to posts_path
end
I'm trying to create a "review" for a specific "review request", but the way I have it set up now it creates a review for a random review request when I select the "Offer a Review" button.
Here's my reviews_controller:
class ReviewsController < ApplicationController
def create
#review = current_user.reviews.build(params[:review_request_id])
if #review.save
flash[:success] = "Review Created"
redirect_to review_path(#review)
else
flash[:error] = "Review Offer Sent"
redirect_to root_url
end
end
def show
#review_request = ReviewRequest.find(params[:id])
end
end
Here's a section of the partial with the link_to the create action:
<span class="offer_review">
<%= link_to "Offer A Review", reviews_path(:review_request_id), :method => :post %>
</span>
I have
belongs_to :review_request
in the models/review.rb file and
belongs_to :user
in the review_request.rb file.
This is the index action in the review requests controller. The partial with the link is in the index view. May be part of the problem?
def index
#review_requests = ReviewRequest.paginate(page: params[:page])
end
try to use 'puts' statement for 'params[:review_request_id]' and check what value you are getting. It seems that the problem is in the definition of the form field.
There were actually two issues here. I solved the first one (the review wasn't being created with the review_request_id) with:
#review_request = current_user.review_requests.build(params[:review_request])
in the review_requests_controller, and:
<%= link_to "Offer A Review", reviews_path(:review_request_id => review_request), :method => :post %>
in the view.
I had actually solved this issue without realizing it before posting this question (and reverted back to the code above) because the redirect to the Review#show controller was wrong as well, and would show information for the wrong review_request even if the review was created correctly. (It did this because it took reviews/1 to be the review_request_id, not the review_id)
This is the code I got that to work right:
#review = Review.find(params[:id])
#review_request = ReviewRequest.find(#review.review_request_id)
Lets say I have a message resource. Somewhere in the html I have:
<%= link_to("Delete", message, :title => 'Delete', :confirm => 'Are you sure?',
:method => :delete )%>
Right after I delete it, it redirects me to the page where it lists all the messages. Is there a way to redirect to a page that I specify after the deletion?
In the controller:
def delete
Item.find(params[:id]).destroy
redirect_to :action => "index"
end
To redirect to the last url, use:
redirect_to :back
http://api.rubyonrails.org/classes/ActionController/Base.html#M000662
If you can learn how to read api docs well, they are extremely useful, once you get the hang of them.
It's actually the destroy action that you should be dealing with if you're using Rails' resources.
def destroy
Item.find(params[:id]).destroy
redirect_to other_specified_path
end
If you look at the API documentation, you'll see there's a HUGE difference between the ActiveRecord::Base#delete and ActiveRecord::Base#destroy methods. Only use delete if you really understand why you're using it.
i only need this
def delete
Item.destroy
redirect_to :back
end
i used this if i want to back to current page