Rails 4 - How do I structure this model relationship?

62 views Asked by At

In my app, I have two models, Task and Guideline. Each Task can have many Guidelines, and each Guideline can belong to many Tasks. How would I set up the relationship between these two models, if it is even possible with ActiveRecord? I have thought about structuring it like so:

class Task < ActiveRecord::Base
  has_many :guidelines
end

class Guideline < ActiveRecord::Base
  belongs_to :task
end

However, my understanding is that belongs_to will associate a Guideline to only one Task by setting its task_id field. This means that, if a given Guideline is assigned to another Task, the first association will be lost. Please correct me if I'm wrong.

I have looked into the has_and_belongs_to_many relationship, but Guidelines cannot have any Tasks; they can only belong to many tasks. I currently have a system in which I store in an array the IDs of all the selected Guidelines for a given Task, but I would prefer to use built-in associations if possible.

Any help would be greatly appreciated.

3

There are 3 answers

2
Austin Ziegler On BEST ANSWER

This is still fundamentally a has_and_belongs_to_many relationship, with a join table:

+-------+     +-----------------+     +------------+
| Tasks |-----| GuidelinesTasks |-----| Guidelines |
+-------+     +-----------------+     +------------+

In reality, your model is that a guideline has many tasks as well as tasks having many guidelines. The fact that a guideline “belongs to many” is how you interpret it is a purely application-level item that has no relationship to the actual data model.

In Rails, you can model this a couple of ways depending on whether your guidelines_tasks table itself has values you wish to track. Both use the same data structure:

# Migration
class AddTasksAndGuidelines < ActiveRecord::Migration
  def change
    create_table :tasks do |t|
      …
    end

    create_table :guidelines do |t|
      …
    end

    create_join_table :guidelines, :tasks
  end
end

With this, the first model is the classic has_and_belongs_to_many:

# habtm
class Tasks < ActiveRecord::Base
  has_and_belongs_to_many :guidelines
end

class Guidelines < ActiveRecord::Base
  has_and_belongs_to_many :tasks
end

The second model—useful if GuidelinesTask has attributes of its own is reflexive has_many through::

class Tasks < ActiveRecord::Base
  has_many :guidelines_tasks
  has_many :guidelines, through: :guidelines_tasks
end

class GuidelinesTask < ActiveRecord::Base
  has_many :tasks
  has_many :guidelines
end

class Guidelines < ActiveRecord::Base
  has_many :guidelines_tasks
  has_many :tasks, through: :guidelines_tasks
end

Either will work.

0
igor_rb On

You can use has_and_belongs_to_many association. It allow you make things like: Task.first.guidlines (and Guidline.first.tasks, if you need).

0
Ankita Tandel On

You can use has_and_belongs_to_many association

Your model code will be

class Task < ActiveRecord::Base

  has_and_belongs_to_many :guidelines

end

class Guideline < ActiveRecord::Base

 has_and_belongs_to_many :tasks

end

Also you need to create a table in database named guidelines_tasks with following migration code create_table :guidelines_tasks, id: false do |t|

  t.belongs_to :guideline, index: true
  t.belongs_to :task, index: true

end