You can simplify your function as follows:
@goal.status = @goals.tasks.map(&:complete).all?
Assuming you want to know as soon as possible whether or not your goal
is complete, you'll want to put this function in your Task
model. You can do it as follows:
def Task < ActiveRecord::Base
belongs_to :goal
after_save :goal_completed
def goal_completed
if self.goal.tasks.map(&:completed).all?
self.goal.update_attribute(:completed, true)
end
end
end
As you can see, if you have a lot of tasks
for one goal
, this could get costly very quickly, since you're pulling all of a goal
's tasks
every time a task
is saved. So, for a larger database, I'd recommend keeping a count of completed tasks for each goal. (This is actually pretty similar to something I implemented in a project of mine.)
To start, you'll need to add a counter cache column in your goals
for tasks_count
(if you haven't already), and add another column to goals
called completed_tasks_count
, or something like that. Make sure they both default to zero.
def Goal < ActiveRecord::Base
has_many :tasks, inverse_of: :goal, counter_cache: true
end
def Task < ActiveRecord::Base
belongs_to :goal, inverse_of: :tasks
after_initial :set_completed_tasks_count, on: new
around_save :goal_complete
def set_completed_tasks_count
self.completed = false if self.new_record? && self.completed.nil?
end
def goal_complete
yield
if self.completed? && !self.completed_was
self.review.increment!(:completed_tasks_count)
elsif (!self.completed? && self.completed_was) || self.marked_for_destruction?
self.review.decrement!(:completed_tasks_count)
end
end
end
Hopefully this helps. Happy coding!