Nested :throughs

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 :slight_smile:

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?

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 :slight_smile:

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?

On Jan 6, 9:30 pm, Melvin R. [email protected]
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

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.