HABTM: deleting records based on attributes


#1

Hello All,

I am new to ROR, and can’t seem to get HABTM to cooperate entirely…
however I might be abusing it! Before I try a different strategy I
thought I’d ask here and see if I’m missing something simple.

So say Projects and Companies are related. Projects can have multiple
Companies, and Companies can be on multiple Projects. But, the same
Company can also be assigned multiple times to the same Project under
different roles.

This all works fine with something like this:

@project.companies.push_with_attributes(company, :role_id =>
params[:role_id])

So I make 2 entries for a Company. One with the role of ‘shipping’, and
one with the role of ‘distribution’. Now how do I remove only one of
the entries? I can only seem to find ways to remove Companies from a
Project based on company_id (which deletes both entries).

@project.companies.delete(company)

I need to be able to do it based on company_id and role_id.

Here are my models:

class Company < ActiveRecord::Base
has_and_belongs_to_many :projects
belongs_to :role
end

class Project < ActiveRecord::Base
has_and_belongs_to_many :companies
belongs_to :role
end

class Role < ActiveRecord::Base
has_many :companies
has_many :projects
end

I feel like I’m really close or else way off, but not sure which :wink:

Thanks for your help,
Paul


#2

you might want to tackle this from another angle…here’s how i would do
it.
not saying its the best way, just that it makes more sense to me…

db schema:

companies

id
name
pk (id)

projects

id
name
pk (id)

roles

id
name
pk (id)

company_project_relationships

id
company_id
project_id
role_id
pk (id)
unique (company_id, project_id, role_id)
fk (company_id)
fk (project_id)
fk (role_id)

class definitions:

class Company < ActiveRecord::Base
has_many :project_relationships, :class_name =>
“CompanyProjectRelationship”, :dependent => :destroy

def add_project_relationship(project, role)
project_relationships.create(:company_id => id, :project_id =>
project.idhttp://project.id,
:role_id => role.id http://role.id) unless
project_relationships.find(id,
:conditions => [“project_id = ? and role_id = ?”,
project.idhttp://project.id,
role.id http://role.id])
end

def remove_project_relationship(project, role)
pr = CompanyProjectRelationship.find(:first, :conditions => [“company_id
= ?
and project_id = ? and role_id = ?”, id, project.id http://project.id,
role.id http://role.id])
project_relationships.delete(pr) unless cpr.nil?
end
end

class Project < ActiveRecord::Base
has_many :company_relationships, :class_name =>
“CompanyProjectRelationship”, :dependent => :destroy

def add_company_relationship(company, role)
company_relationships.create(:company_id => company.id
http://company.id,
:project_id => id, :role_id => role.id http://role.id)
end

def remove_company_relationship(company, role)
cr = CompanyProjectRelationship.find(:first, :conditions => [“company_id
= ?
and project_id = ? and role_id = ?”, company.id http://company.id, id,
role.id http://role.id])
ccompany_relationships.delete(cr) unless cpr.nil?
end
end

class CompanyProjectRelationship < ActiveRecord::Base
belongs_to :role
belongs_to :company
belongs_to :project
end

class Role < ActiveRecord::Base
has_many :cprs, :class_name => “CompanyProjectRelationship”
end

given the following data:

companies = 1, ‘Company A’ and 2, ‘Company B’
projects = 1, ‘Project 1’ and 2, ‘Project 2’
roles = 1, ‘shipper’ and 2, ‘distributer’

you could do:

project = Project.find(1)
companies = Company.find(:all)
roles = Roles.find(:all)

project.add_company_relationship(companies[0], roles[0])
project.add_company_relationship(companies[0], roles[1])

this will add 2 rows to company_project_relationships table, making
Company
A both the shipper and distributer for Project 1

to remove a particular relationship, just do:

project.remove_company_relationship(company, roles[0]) … or …
companies[0].remove_project_relationships(project, role[0])

this would remove Company A as the shipper for Project 1

note, since this was just an example, there’s no real error checking.

hope this helps…

Chris