How Rails: If a project has tasks it should not be deleted: how can I fix this?

248 views Asked by At

Hi I have a project and each project has tasks. A task belongs to a project. Before I delete a project I want to check if there are related tasks. If there are tasks I don't want to delete the project. If there are no associated tasks, the project should be deleted. Can you please help me with the code? What am I missing?

class Project < ActiveRecord::Base  
  before_destroy :check_tasks    

  def check_tasks 
    if Project.find(params[:id]).tasks  
      flash[:notice] = 'This project has tasks.'
      redirect_to :action => 'list_projects'    
    end 
  end
end
3

There are 3 answers

1
Brett Bender On

You have a couple of problems here.

  1. You don't (or shouldn't) have access to the params variable (it's available in controllers and views only, unless you're passing it to the model, which is probably not what you want).
  2. Your if checks against project.tasks which is an array - even an empty array evaluates to true, so your other code branch will never occur no matter if the project has tasks or not.
  3. You should probably be setting error messages for the view from your ProjectsController#destroy action, not in your model.

Solutions:

  1. Change Project.find(params[:id]) to self - you want to check the tasks for every instance of the Project.
  2. Change the check in your if statement from if self.tasks to if self.tasks.any? which returns the value you want (false if the array is empty, true otherwise).
  3. Move the flash[:notice] from your model to your controller, as well as the redirect_to call, where they belong. This means your check_tasks method can be changed to the following:

code:

def check_tasks
  return !self.tasks.any?
end
6
Pasted On

Should the check be self instead? (not sure where you getting the params[:id] from).

Haven't checked this out yet though - but since I need something similar for my Users model I'll see how that works out and get back to you.

class Project < ActiveRecord::Base  
 before_destroy :check_tasks

 private

 def check_tasks
   #edited 
   if tasks.empty?  
     false
   end 
 end
3
AudioBubble On

Return false from the before_destroy method to prevent the instance from being destroyed.

The method should also return a meaningful error for troubleshooting.

class Project < ActiveRecord::Base
  before_destroy :check_tasks

  def check_tasks
    if self.tasks.any?
      errors.add_to_base "Project has tasks and cannot be destroyed."
      return false
    end
  end
end

Note: flash[:notice] and params[:attr_name] can only be used from controllers.