Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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
like image 849
Runy Avatar asked Nov 17 '11 16:11

Runy


2 Answers

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.

like image 91
nslocum Avatar answered Dec 26 '22 01:12

nslocum


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
like image 25
Brett Bender Avatar answered Dec 26 '22 02:12

Brett Bender