7

我有三个类:Person、Position 和 Directory。

  • 一个人 has_many :directories, :through => :position。
  • 目录 has_many :people, :through => :position。
  • Person 和 Directory 都有很多 :positions。
  • Position 模型除了具有id、person_id 和directory_id 之外,还具有一个或多个附加字段(例如,title)。

我希望能够在每次将人员添加到 Directory.people 集合时将数据添加到连接模型,例如标题字段。通常的 << 运算符不会削减它。身份证:

directory = Directory.last     # Let's assume that retrieves a Directory object
person = Person.last           # Let's assume that retrieves a Person object
directory.people << person

这会将一个人添加到 Directory 对象的人员集合中,但不允许我将数据分配给连接模型。所以,在对这个网站做了很多研究之后,我找到了另一种方法来将 Person 添加到 people 集合中,并将数据添加到连接 Person 和 Directory 的 Position 中,id est:

directory = Directory.last     # Let's assume that retrieves a Directory object
person = Person.last           # Let's assume that retrieves a Person object
position = person.positions.build(:directory_id => directory.id, :title => "Administrative Assistant") 
position.save

这很麻烦。一个同样繁琐的方法是:

directory = Directory.last     # Let's assume that retrieves a Directory object
person = Person.last           # Let's assume that retrieves a Person object
position = Position.new(directory_id: directory.id, person_id: person.id, title: "Administrative Assistant")

同样,这似乎是错误的,因为我希望能够强调 Person 和 Directory 之间的关系,我相信这就是使用 has_many :through 适当的原因。

我想做的是使用 << 运算符,然后传递其他数据,例如:

directory = Directory.last # Let's assume that retrieves a Directory object
person = Person.last # Let's assume that retrieves a Person object
directory.people << person, :position => {:title => "Administrative Assistant"}

我在 has_many :through 声明中重载了 << 运算符,如下所示:

has_many :people, :through => :positions do
  def << *args
    arg = args.first
    if arg.is_a?(Person)
      self.push([arg]) 
    elsif arg.is_a?(Hash)
      # Don't know what to do in here (see below)
    else
      raise "Invalid Value" # There's a better error to raise here, but good enough for now.
    end
  end
end

让它工作的优点是它在语法上运行良好,并且允许我在将 Person 添加到 Directory 对象的人员集合时简洁地将数据分配给连接对象(位置)。

但我不能让它工作,因为我需要能够访问 << 运算符左侧的人员集合是一个属性的 Directory 对象,以便构建一个 Position 并将其保存到数据库中。

所以,我的问题是:

  1. 有没有办法从对象的属性访问对象?
  2. 或者,是否有另一种方法可以重载 << 运算符,以便我可以在将一个对象添加到集合时轻松地将数据分配给连接模型?

非常感谢您的帮助和周到的答复。我一直在破解这个半天无济于事。

回答 感谢 PinnyM,他回答了这个问题,我能够想出这个实现:

module AddToPeopleAndPositionExtension
  def << *args
    arg = args.first
      if arg.is_a?(Person)
        self.push([arg]) 
        return self
      elsif arg.is_a?(Hash)
        directory = proxy_association.owner
        person = arg[:person]
        position = person.positions.build(:directory_id => directory.id, :title => arg[:position][:title]) 
        position.save
      else
        raise "Invalid Value"
      end
  end
end

class Directory < ActiveRecord::Base  
  # Relationships
  has_many :positions
  has_many :people, :through => :positions, :extend => AddToPeopleAndPositionExtension
end

如果我不关心连接模型上发生的情况,这允许我以标准方式调用 << 运算符,例如:

directory = Directory.last     # Let's assume that retrieves a Directory object
person = Person.last           # Let's assume that retrieves a Person object
directory.people << person

而且,我还可以以指定连接模型属性的方式调用它,例如:

directory = Directory.last     # Let's assume that retrieves a Directory object
person = Person.last           # Let's assume that retrieves a Person object
directory.people << {:person => person, :position => {:title => "Administrative Assistant"}}
4

1 回答 1

11

您可以使用proxy_association块内的帮助程序来获取关联并proxy_association.owner获取 Directory 对象本身。有关这方面的更多信息,请参见此处。

于 2012-10-11T19:28:22.750 回答