覆盖has_many上的ActiveRecord <<运算符:通过关系,接受连接模型的数据

我有三个类:人员,职位和目录。

  • 一个人has_many:目录,:通过=>:位置。
  • 目录has_many:people,:through =>:position。
  • Person和Directory has_many:position。
  • 除了具有id,person_id和directory_id之外,Position模型还具有一个或多个附加字段(例如,标题)。

我希望能够做的是每次我将一个人添加到Directory.people集合时,将数据添加到连接模型,例如标题字段。 通常的<<运营商不会削减它。 Id est:

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对象的people集合中,但不允许我有机会将数据分配给连接模型。 因此,在对该网站进行了大量研究之后,我发现了另一种方法将Person添加到人员集合中,并将数据添加到链接Person和Directory的位置,id:

 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的原因:通过适当的。

我希望能够做的是使用<<运算符,只需传递其他数据,例如:

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

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

 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对象的people集合。

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

所以,我的问题是:

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

非常感谢您的帮助和深思熟虑的回复。 我一直在这里乱砍半天无济于事。

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

 module AddToPeopleAndPositionExtension def < directory.id, :title => arg[:position][:title]) position.save else raise "Invalid Value" end end end class Directory  :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, :position => {:title => "Administrative Assistant"}} 

您可以使用块内的proxy_association助手来获取关联,并使用proxy_association.owner来获取Directory对象本身。 有关详细信息,请参阅此处 。