Luis D Urraca
Luis D Urraca

Reputation: 2084

how to implement RoR many-to-many relationship?`

I have the following models:

Technician
- id
- name
- personal_id

Tool
- id
- internal_code
- name
- category

A technician can have many tools and one tool can be assigned to many technician (do I really need many-to-many relationship, as I'm typing this I have my doubts). My problem is that I also need to track the quantity of the tool that the technician have under his possession. One record should be like [technician_id, tool_id, quantity]. I have read about the has_many through, but i have not seen an example that fit my problem, what should the structure of the resulting table and also how should I set up the model for tools under the technician possession?

Upvotes: 2

Views: 892

Answers (2)

Brian
Brian

Reputation: 6840

It seems like you are looking for a many-to-many association here. This should work for you given the requirements you set:

class Technician < ActiveRecord::Base
  has_many :assignments
  has_many :tools, :through => :assignments
end

class Tool < ActiveRecord::Base
  has_many :assignments
  has_many :technicians, :through => :assignments
end

class Assignment < ActiveRecord::Base
  belongs_to :tool
  belongs_to :technician
end

Hope it helps.


UPDATE

Thinking about your comment about having a quantity field in Assignments, I'm assuming you are wanting to be able to assign many of the same Tool to a Technician. For example:

>> Technician.new(:name => "Bob").save
=> true
>> Tool.new(:name => "hammer").save
=> true
>> Tool.new(:name => "saw").save
=> true
>> t = Technician.first
=> #<Technician id: 1, name: "Bob", personal_id: nil, created_at: "2011-07-07 22:56:53", updated_at: "2011-07-07 22:56:53">
>> t.tools << [Tool.first, Tool.last]
=> [#<Tool id: 1, name: "hammer", internal_code: nil, category: nil, created_at: "2011-07-07 22:56:22", updated_at: "2011-07-07 22:56:22">, #<Tool id: 2, name: "saw", internal_code: nil, category: nil, created_at: "2011-07-07 22:56:30", updated_at: "2011-07-07 22:56:30">]
>> t.save
=> true
>> t.assignments
=> [#<Assignment id: 1, technician_id: 1, tool_id: 1, quantity: nil, created_at: "2011-07-07 23:01:53", updated_at: "2011-07-07 23:01:53">, #<Assignment id: 2, technician_id: 1, tool_id: 2, quantity: nil, created_at: "2011-07-07 23:02:46", updated_at: "2011-07-07 23:02:46">]
>> a = t.assignments.first
=> #<Assignment id: 1, technician_id: 1, tool_id: 1, quantity: nil, created_at: "2011-07-07 23:01:53", updated_at: "2011-07-07 23:01:53">
>> a.quantity = 5
=> 5
>> a.save
=> true
>> t.assignments.first.quantity
=> 5
>> 

If this is not the case, let me know & I can update with another approach.

Upvotes: 2

Matthew Lehner
Matthew Lehner

Reputation: 4027

It sounds like this is the perfect place to use a HABTM relationship type. You'll want to do the following:

Run the following migration:

class AddTechniciansToolsJoinTable < ActiveRecord::Migration
  def self.up
    create_table :technicians_tools, :id => false  do |t|
      t.integer :technician_id, :null => :false
      t.integer :tool_id, :null => :false
    end
    add_index :technicians_tools, [:technician_id, :tools_id], :unique => true
  end

  def self.down
    drop_table :technicians_tools
  end
end

Add the following to your models:

class Technician < ActiveRecord::Base
  has_and_belongs_to_many :tools
end

class Tool < ActiveRecord::Base
  has_and_belongs_to_many :technicians
end

This will allow you to use a number of Rails methods which are specific to a HABTM relationship such as technician.tools.size for a count of the tools available to that specific technician.

For more info, have a look at the Rails guides about HABTM relationships here: http://edgeguides.rubyonrails.org/association_basics.html#has_and_belongs_to_many-association-reference

Upvotes: 3

Related Questions