1

a rails newbie here, looking at doing some work with 4 tables and not totally sure how to structure the associations. Below topic involves real estate, probably helpful to keep that in mind.

I have four models:

  • Property - a physical house
  • Project - a large group of jobs happening at a house
  • Job - a specific job at a house
  • Worker - a person doing the work

The associations as I see them in my head are:

  • a Property can have many Projects, Jobs, and Workers
  • a single Project belongs to one Property, but can have many Jobs and (via Jobs) have many Workers
  • a single Job belongs to one Project and to one Property (via the Project), but can have many Workers
  • a single Worker can have one Job on one Projects on one Property

My two questions are:

  1. What is the best way to think about the above set of relationships?

  2. ** How do I build the associations between my models? Can't get my head wrapped around how to do that.

Really appreciate any thoughts!

***** UPDATED MODEL STRUCTURE - 9/30/2015 Thanks Jason - here is what I have now (below)

My key goal in working with the data will be the following: - list a property, it's projects, jobs and workers - list a set of projects and properties for a worker

Does the below model structure accomplish the above? It seems to from my view but can't totally be sure.

Model setup as 9/30

  • Property Model has_many :projects has_many :jobs, through: :projects has_many :workers, through: :jobs

  • Project Model belongs_to :property has_many :jobs has_many :workers, through: :jobs

  • Job Model belongs_to :project has_many :workers

  • Worker Model has_many :jobs

Anthony
  • 67
  • 5
  • Check out http://guides.rubyonrails.org/association_basics.html. There you will learn about different types of associations, when to use which and how to set them up. – IngoAlbers Sep 29 '15 at 18:08
  • Thanks Egon, yeah I've seen that before. It all "makes sense" when I read it but then when I try to do it for some reason it all turns into a mess... – Anthony Sep 29 '15 at 18:09

1 Answers1

1

To clarify, I think you have this: A property can have many projects. Each project belongs to one property and can have many jobs. Each job belongs to one project and can have many workers. Each worker belongs to one job.

Property model:

has_many :projects

Project model:

belongs_to :property
has_many :jobs

Job model:

belongs_to :project
has_many :workers

Worker model:

belongs_to :job

Each project should have a property_id, each job should have a project_id and each worker should have a job_id. These can be established in your migration (with the belongs_to function) where you create the tables for these models. They'll look like this:

create_table :projects do |t|
  t.belongs_to :property, index: true
  .
  . # your other attribute(s) here
  .
end

That will give the Project model a property_id attribute, allowing you to access a Project's Property.

Edit:

If you want to easily access all of a property's workers and all of a project's workers, you can add a has_many through association to each of the Property and Project models. Also, you can add another association to the Property model that will allow you to access all of a property's jobs. They will look like this:

Property model additions:

has_many :jobs, through: :projects
has_many :workers, through: :projects

Project model additions:

has_many :workers, through: :jobs

Edit: (OP clarified desired model scheme)

Now if we want to have it so a worker can be assigned to more than one property, a different type of association will be needed. First of all, this association will only need to handle the relationship between jobs and workers. Since every job has only one parent project, and every project has only one parent property, the project and property associated with any job that a worker has will be accessible through that job.

There are two options for this job to worker relationship: has_and_belongs_to_many and has_many through. The key difference between these options is that each record in the has_and_belongs_to_many join table will only establish the association between a job and a worker and would not require a model, but the has_many through join table can contain additional information about that association. That additional information would be accessed through a separate model. This second option could, for example, be useful for keeping track of the number of hours that a worker logged on each job. Here is a more thorough description of the difference between these options.

If you have already created the Worker and Job models, you should generate a new migration to create this join table. Otherwise, you can include the following create_table in the migration file for the Worker or Job models.

Here is the migration code for a has_and_belongs_to_many association:

def change
  create_table :jobs_workers do |t|
    t.belongs_to :job, index: true
    t.belongs_to :worker, index: true
  end
end

In the Job model, get rid of this:

has_many :workers

and replace it with this:

has_and_belongs_to_many :workers

In the Worker model, get rid of this:

belongs_to :job

and replace it with this:

has_and_belongs_to_many :jobs

An explanation of the has_many through association would be more lengthy, so I'll defer to this page.

Jason
  • 2,725
  • 2
  • 14
  • 22
  • Hi Jason, really really appreciate your thoughts here. Comment / questions... 1) in my case a worker will only belong to 1 job 2) in your above "property model addition"...is it: has_many :jobs, through: :projects has_many :workers, through: :projects - or - has_many :jobs, through: :projects has_many :workers, through: :jobs Note the 2nd line of "through: :projects" vs. "through: :jobs" likewise, can I still find a list of properties via 1 worker this way? – Anthony Sep 30 '15 at 00:48
  • 1
    Either of those will allow you to access all of the workers that are associated with a property. I'm confused about the last part of your comment, though, where you ask if you can "find a list of properties via 1 worker." I thought a worker, through their job and then their job's project, could only be associated with one property. Is that not accurate? – Jason Sep 30 '15 at 01:39
  • Well this is where perhaps I am thinking incorrectly. For example, a worker could work on multiple properties, i.e. 10 Happy Street on Monday and then 20 Silly Street on Friday... worker in this case is best thought of as an electrician / plumber, etc. so someone that could easily work on either one property a few times, or across multiple properties; however, at any point in time they are only working on 1 job at 1 property. So you could imagine that you would want to find "what are all the properties that Bob has worked at?" make sense? – Anthony Sep 30 '15 at 03:09
  • 1
    See my above edit and keep the questions coming whenever they come up! – Jason Sep 30 '15 at 15:38
  • Thanks Jason - I updated the question based on our discussion - see the original question and look / search for the "UPDATED MODEL" Think I somehow prefer the "through:" approach, seems more clear to me and I might add to models later...(thanks again!) – Anthony Sep 30 '15 at 23:35
  • Hi Jason, did that updated model association look right? Thanks! – Anthony Oct 01 '15 at 20:43
  • 1
    Your associations between `:workers` and `:jobs` don't include the model that you need to be able to assign many workers to a job and vice versa. You said you were going to go with a `has_many` `through` association. That association needs a model that parallels the configuration seen [here](http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association), where their `Physician` and `Patient` correspond to your `Job` and `Worker`. The model (and join table) you need to create for this association corresponds to their `Appointment`. – Jason Oct 01 '15 at 21:08