I need some help with a rails development that I'm working on, using rails 3. This app was given to me a few months ago just after it's inception and I have since become rather fond of Ruby.
I have a set of Projects that can have resources assigned through a teams table.
A team record has a start date and a end date(i.e. when a resource was assigned and de-assigned from the project).
If a user has been assigned and deassigned from a project and at a later date they are to be assigned back onto the project, instead of over writting the end date, I want to create a new entry in the Teams table, to be able to keep a track of the dates that a resource was assigned to a certain project.
So my question is, is it possible to have multiple entries in a :has_many through association?
Here's my associations:
class Resource < ActiveRecord::Base
has_many :teams
has_many :projects, :through => :teams
end
class Project < ActiveRecord::Base
has_many :teams
has_many :resources, :through => :teams
end
class Team < ActiveRecord::Base
belongs_to :project
belongs_to :resource
end
I also have the following function in Project.rb:
after_save :update_team_and_job
private
def upda开发者_JAVA技巧te_team_and_job
# self.member_ids is the selected resource ids for a project
if self.member_ids.blank?
self.teams.each do |team|
unless team.deassociated
team.deassociated = Week.current.id + 1
team.save
end
end
else
self.teams.each do |team|
#assigning/re-assigning a resource
if self.member_ids.include?(team.resource_id.to_s)
if team.deassociated != nil
team.deassociated = nil
team.save
end
else
#de-assigning a resource
if team.deassociated == nil
team.deassociated = Week.current.id + 1
team.save
end
end
end
y = self.member_ids - self.resource_ids
self.resource_ids = self.resource_ids.concat(y)
self.member_ids = nil
end
end
end
Sure, you can have multiple associations. has_many takes a :uniq option, which you can set to false, and as the documentation notes, it is particularly useful for :through rel'ns.
Your code is finding an existing team and setting deassociated though, rather than adding a new Team (which would be better named TeamMembership I think)
I think you want to just do something like this:
add an assoc for active memberships (but in this one use uniq: => true:
has_many :teams has_many :resources, :through => :teams, :uniq => false has_many :active_resources, :through => :teams, :class_name => 'Resource', :conditions => {:deassociated => nil}, :uniq => true
when adding, add to the active_resources if it doesn't exist, and "deassociate" any teams that have been removed:
member_ids.each do |id| resource = Resource.find(id) #you'll probably want to optimize with an include or pre-fetch active_resources << resource # let :uniq => true handle uniquing for us end teams.each do |team| team.deassociate! unless member_ids.include?(team.resource.id) # encapsulate whatever the deassociate logic is into a method end
much less code, and much more idiomatic. Also the code now more explicitly reflects the business modelling
caveat: i did not write a test app for this, code may be missing a detail or two
精彩评论