0

Context:

I have a Company model that has many projects. Each project has many tasks. The company has many employees.

The Employee model is associated with Company and not with projects or tasks. The Task model does have a employee_name attribute, since it is one employee per task (but more task per employee). An employee will have only one task per project.

Schema:

My question:

I'm trying to create an array that for each employee stores the projects it has a task in.

I currently have the following code working, but I am wondering if I could do this in a better way. Should I change my model associations, or is this the way to go?

        @employee = Employee.find(1)
        @employee_tasks = Task.where(employee: @employee.name)

        @employee_project = {}
        i = 0

        @employee_tasks .each do |f|
            i += 1
            @employee_project[i] = Project.where(id: f.project_id)              
        end
7
  • 3
    Why can't you replace the employee_name on task with a belongs_to :employee? For me it'd be cleaner and to display the employee's name you can delegate to the employee. Then you can have a has_many :projects, through: :tasks on employee Commented Feb 17, 2016 at 15:41
  • It's not clear what you're trying to do so it's hard to suggest a refactor, but "@employee.company.projects" will give you the projects associated with an employee. Commented Feb 17, 2016 at 15:43
  • @MaxWilliams that gives all projects that the employee's company has. I think he's wanting all projects where the employee has a task Commented Feb 17, 2016 at 15:46
  • @MaxWilliams, @j-dexx, indeed I am looking for an array that contains all projects in which the employee has a task. You are right the above example begs the question if I have set up my model associations the right way. Are you saying I should simply make Task belong to both Project and Employee? Commented Feb 17, 2016 at 16:04
  • @MatthiasHavenaar Yes, you should associate it. Commented Feb 17, 2016 at 16:06

1 Answer 1

1
class Project
  has_many :tasks
end

class Task
  belongs_to :project
  belongs_to :employee

  delegate :name, to: :employee, prefix: true
end

class Employee
  has_many :tasks
  has_many :projects, through: :tasks
end

I assume in your view you currently have this for a task

<%= task.employee_name %>

By using the prefix option on the delegate method this will still work if you associate your models in this way.

So now in your controller you could do

@employee = Employee.find(1)
@employee_tasks = @employee.tasks

Then say later on you wanted to find the employee's on a project and list them somewhere. Then you simply add to project

class Project
  has_many :tasks
  has_many :employees, through: :tasks
end

@project = Project.find(1)
@project_tasks = @project.tasks

Associating tasks to employees properly makes this much simpler. Another benefit is what happens if an employee changes their name? Currently you'd need to go through all the tasks to change the employee name on the task too (or write code to do it if an employee changed their name). By using the association you'd just change the employees name and it'd just work.

Sign up to request clarification or add additional context in comments.

3 Comments

I have assumed that employee has a name method here though.
Thanks a lot. This probably is the answer. I'll accept it once I have figured out how to refactor my code and manage to implement your suggestion. Cheers!
In case you feel helpful ;-) Follow up question following your answer: stackoverflow.com/questions/35469738/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.