Give an error when a model is deleted in Rails - ruby-on-rails

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

Related

Rails Delete doesn't destroy record, simply refreshes

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).

How do I get flash[:notice] to display in my view?

I'm having difficulty getting my notices to display in my Rails 5 view. I have this before_filter method set up in a controller:
def check_email_confirmed!
redirect_to controller: "users", action: "edit", notice: 'Please confirm your email.' unless current_user.email_confirmed
end
and in my view I have this
<% if flash[:notice] %>
<p class="flash-notice"><%= flash[:notice] %></p>
<% end %>
but despite the fact that I know the notice is getting set (I see it in my URL) the above is not getting invoked in my view (I see no HTML with the class="flash-notice").
Is there some other way I should be setting flash notices in a redirect? Or should I be using a redirect at all (someone told me there might be some security risks in embedding messages in the URL query string)?
You're currently setting a parameter with the key notice, not setting the flash in your session.
To accomplish this the way you're doing it you would have to do:
<p class="flash-notice"><%= params[:notice] %></p>
Most Rails apps that I've worked on set the session[:flash] in the controller method, in which case you would do:
unless current_user.email_confirmed
redirect_to edit_user_path(current_user)
flash[:notice] = 'Please confirm your email.'
end
Unless you have a good reason to pass the notice text as a URL param, I'd recommend doing it this way.
Try
flash[:notice] = 'bla'
redirect_to controller: "users", action: "edit"
I'm pretty sure that
redirect_to edit_user_path(user), notice: 'bla'
Will also work. For some reason your syntax apparently doesn't pick up the notice modifier. But you'll have to assign user to your current user for that to work obviously.

How do I display the name of a deleted element in Ruby on Rails?

I have a simple Rails application where I create objects (such as posts). So far I can edit and delete them, one by one, but now I want to have a <%= notice %> echoing the name of the deleted object after confirming its deletion. Is this possible? If so, how?
This is an extremely common task in Rails, and the idiomatic solution is to forward some data about the deleted record to the subsequent GET request via the the flash array.
Your controller's destroy action should look something like this:
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to posts_path, notice: "#{#post.name} was deleted"
end
In your index action, you'll be able to access flash[:notice] to get the string generated in the previous action.
You need to store the details you want to echo (e.g. the name) somewhere, because the object itself will be gone after a redirect. I would use the flash for that:
# in the controller
def destroy
thing = Thing.find(params[:id])
thing.destroy
redirect_to things_path, :notice => "Thing #{thing.name} was deleted"
end
# in the index view
<% if flash[:notice] %>
<div class="notice"><%= flash[:notice] %></div>
<% end %>

build method in create action of controller is creating to the wrong user

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)

Undefined method `destroy' for "Tech":String

When I go to delete a post I keep receiving an error that says
undefined method `destroy' for "Tech":String
The "tech" part of the posts varies with whatever the tag is of the post I am trying to delete. I am not sure what the problem is. I am using acts_as_taggable_on if that has anything to do with it.
This is my destroy method in my posts controller:
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to(root_path) }
format.xml { head :ok }
format.json { head :ok }
end
end
The delete button in my post show:
<%= button_to 'Delete', #post, :method => :delete, :confirm => "Are you sure?" %>
Tags are saved in the database as a string.
It's impossible to give you an answer to fix your problem, because you are giving no code and no examples.
Nonetheless that error means you are calling the destroy method on a string, and strings in Ruby do not have a destroy method defined.
Check where are you calling destroy, because it seems you are doing it in some function that returns a string (a tag name in your case). You must do it on an object that is an instance of the Tag class.

Resources