Несколько записей в: has_many через ассоциацию - PullRequest
4 голосов
/ 22 августа 2011

Мне нужна помощь в разработке rails, над которой я работаю, используя rails 3. Это приложение было дано мне несколько месяцев назад сразу после его появления, и с тех пор я очень полюбил Ruby.

У меня есть набор проектов, которым можно назначить ресурсы через таблицу команд.

Запись команды имеет дату начала и дату окончания (т. Е. Когда ресурс был назначен и отменен из проекта).

Если пользователь был назначен и отозван из проекта, а позднее он будет возвращен обратно в проект, вместо перезаписи даты окончания я хочу создать новую запись в таблице «Команды», чтобы иметь возможность отслеживать даты, когда ресурс был назначен определенному проекту.

Итак, мой вопрос: возможно ли иметь несколько записей в: has_many через ассоциацию?

Вот мои ассоциации:

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

У меня также есть следующая функция в Project.rb:

after_save  :update_team_and_job

private
  def update_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

1 Ответ

0 голосов
/ 22 августа 2011

Конечно, вы можете иметь несколько ассоциаций.has_many принимает параметр: uniq, который можно установить на false, и, как отмечается в документации, он особенно полезен для: through rel'ns.

Ваш код находит существующую команду и, тем не менее, деассоцирует настройкучем добавление новой команды (которую, я думаю, лучше назвать TeamMembership)

Я думаю, вы хотите просто сделать что-то вроде этого:

  1. добавить ассоциацию для активных участников(но в этом случае используйте 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
    
  2. при добавлении, добавьте к active_resources, если он не существует, и «деассоциируйте» любые команды, которые былиудалено:

    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
    

гораздо меньше кода и гораздо более идиоматично. Также код теперь более явно отражает бизнес-моделирование

предостережение: я не писал тестприложение для этого, код может отсутствовать деталь или два

...