# Nested :throughs

**URL:** <https://www.ruby-forum.com/t/nested-throughs/125220>\
**Category:** Rails\
**Created:** [January 7, 2008, 6:18am UTC](https://www.ruby-forum.com/t/nested-throughs/125220 "2008-01-07T06:18:37Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![danhobbs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/a5b964/32.png) [@danhobbs](https://www.ruby-forum.com/u/danhobbs)\
**Post date:** [January 7, 2008, 6:18am UTC](https://www.ruby-forum.com/t/nested-throughs/125220/1 "2008-01-07T06:18:37Z")

</div>

Hi Guys, First off: Rails is amazing: Thanks! I’ve been trying unlearn  
everything I know about web development and it is tricky - I’m not used  
to things being beautiful 🙂

Anyway, I think I might be over complicating this but I’m working on a  
project that tracks progress towards earning an award. Each award has  
several groups of tasks and each group has one or more tasks. I have  
defined the Award class below:

Class Award \< ActiveRecord::Base  
has\_many :task\_groups  
has\_many :tasks, :through =\> :task\_groups

end

The completed tasks for each user is tracked in a table called  
completed\_tasks. And I want to show how many tasks the user has  
completed for a particular award (and how many remain).

Here is what I tried:

Class Award \< ActiveRecord::Base  
has\_many :task\_groups  
has\_many :tasks, :through =\> :task\_groups  
has\_many :completed\_tasks, :through =\> :tasks

def completed\_tasks\_for\_user(user)  
completed\_tasks.find\_by\_user\_id(user.id)  
end  
end

Class Task \< ActiveRecord::Base  
has\_many :completed\_tasks

end

I was hoping that Active record would join awards to task\_groups, then  
to tasks, then to completed\_tasks but the generated SQL was:

SELECT completed\_tasks.\* FROM completed\_tasks INNER JOIN tasks ON  
completed\_tasks.task\_id = tasks.id WHERE ((tasks.award\_id = 3)) AND  
(`completed_tasks`.`user_id` = 1) LIMIT 1

There is no award\_id in the tasks table so the above statement doesn’t  
work. It needs to go through the task\_group table first.

I know I could iterate through the tasks and get the completed tasks for  
a user that way but thought there might be a more ruby-licious way. Any  
ideas?

---

<div class="post-metadata">

**Author:** ![danhobbs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/a5b964/32.png) [@danhobbs](https://www.ruby-forum.com/u/danhobbs)\
**Post date:** [January 7, 2008, 6:30am UTC](https://www.ruby-forum.com/t/nested-throughs/125220/2 "2008-01-07T06:30:24Z")

</div>

Why not just have an extra field in the Task model called completed  
(boolean). Next, create a method in the Task model that looks something  
like this:

def tasks\_completed\_by\_user(user)  
find(:all, :conditions =\> {“user\_id = ‘#{user}’”, “completed = ‘1’”)  
end

That would give you a collection of Tasks that are marked completed.

Now I am a ROR newbie so the code above may need some tweaking… but  
you get the idea.

Dan Hixon wrote:

> Hi Guys, First off: Rails is amazing: Thanks! I’ve been trying unlearn  
> everything I know about web development and it is tricky - I’m not used  
> to things being beautiful 🙂
> 
> Anyway, I think I might be over complicating this but I’m working on a  
> project that tracks progress towards earning an award. Each award has  
> several groups of tasks and each group has one or more tasks. I have  
> defined the Award class below:
> 
> Class Award \< ActiveRecord::Base  
> has\_many :task\_groups  
> has\_many :tasks, :through =\> :task\_groups
> 
> end
> 
> The completed tasks for each user is tracked in a table called  
> completed\_tasks. And I want to show how many tasks the user has  
> completed for a particular award (and how many remain).
> 
> Here is what I tried:
> 
> Class Award \< ActiveRecord::Base  
> has\_many :task\_groups  
> has\_many :tasks, :through =\> :task\_groups  
> has\_many :completed\_tasks, :through =\> :tasks
> 
> def completed\_tasks\_for\_user(user)  
> completed\_tasks.find\_by\_user\_id(user.id)  
> end  
> end
> 
> Class Task \< ActiveRecord::Base  
> has\_many :completed\_tasks
> 
> end
> 
> I was hoping that Active record would join awards to task\_groups, then  
> to tasks, then to completed\_tasks but the generated SQL was:
> 
> SELECT completed\_tasks.\* FROM completed\_tasks INNER JOIN tasks ON  
> completed\_tasks.task\_id = tasks.id WHERE ((tasks.award\_id = 3)) AND  
> (`completed_tasks`.`user_id` = 1) LIMIT 1
> 
> There is no award\_id in the tasks table so the above statement doesn’t  
> work. It needs to go through the task\_group table first.
> 
> I know I could iterate through the tasks and get the completed tasks for  
> a user that way but thought there might be a more ruby-licious way. Any  
> ideas?

---

<div class="post-metadata">

**Author:** ![danhobbs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/a5b964/32.png) [@danhobbs](https://www.ruby-forum.com/u/danhobbs)\
**Post date:** [January 7, 2008, 8:03pm UTC](https://www.ruby-forum.com/t/nested-throughs/125220/3 "2008-01-07T20:03:37Z")

</div>

On Jan 6, 9:30 pm, Melvin R. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Why not just have an extra field in the Task model called completed  
> (boolean). Next, create a method in the Task model that looks something  
> like this:

I’m with Melvin. Ideally, an object/entity shouldn’t change its class/  
table just because its state has changed.

///ark

---

<div class="post-metadata">

**Author:** ![danhobbs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/a5b964/32.png) [@danhobbs](https://www.ruby-forum.com/u/danhobbs)\
**Post date:** [January 7, 2008, 8:05pm UTC](https://www.ruby-forum.com/t/nested-throughs/125220/4 "2008-01-07T20:05:10Z")

</div>

Thanks for the replies Mark and Melvin.

Since the tasks can indirectly belong to many users at once I couldn’t  
simply add a completed boolean to that class. (“Run a mile under 6  
minutes” might be completed by Jeremy but not yet by Alex).

I ended up adding this method to my user model:

def completed\_tasks\_in\_current\_award  
tasks = []  
completed\_tasks.each do |ct|  
if ct.task.task\_group.award == award  
tasks \<\< ct.task  
end  
end  
tasks  
end

I’m guessing there might be a way to do it with more code - but this  
will suffice for now.
