覆盖的ActiveRecord<<运营商的的has_many:通过关系,以接受连接模型数据 [英] Override ActiveRecord << operator on has_many :through relationship, to accept data for the join model

查看:153
本文介绍了覆盖的ActiveRecord<<运营商的的has_many:通过关系,以接受连接模型数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有三类:个人,位置,和目录

  • 在一个人的has_many:目录:通过=>:位置
  • 在一个目录的has_many:人:通过=>:位置
  • 人物都和目录的has_many:位置
  • 的定位模型,除了具有一个ID,一个为person_id,和一个directory_id,具有一个或多个附加字段(例如,标题)。

我希望能够做的就是将数据添加到加盟模式,比如title字段,我每次加一个人到Directory.people集合。通常<<运营商将不会削减它。编号斯:

 目录= Directory.last#假设检索目录对象
人= Person.last#假设检索一个Person对象
directory.people<<人
 

这将增加一个人的目录对象的人的集合,但不会让我有机会的数据分配给连接模型。所以,做了很多的研究,这个网站后,我发现了另一种方式的个人数据添加到人收藏,并添加到链接的人事和目录的位置,ID斯:

 目录= Directory.last#假设检索目录对象
人= Person.last#假设检索一个Person对象
位置= person.positions.build(:directory_id => directory.id,:标题=>中行政助理)
position.save
 

这是麻烦的。同样麻烦的方式是:

 目录= Directory.last#假设检索目录对象
人= Person.last#假设检索一个Person对象
位置= Position.new(directory_id:directory.id,PERSON_ID:person.id,标题:行政助理)
 

此外,似乎错了,因为我希望能够强调个人​​和目录之间的关系,我相信这是什么使用的has_many:通过适当的

我希望能够做的是使用的<<运营商,只是通过额外的数据,如:

 目录= Directory.last#假设检索目录对象
人= Person.last#假设检索一个Person对象
directory.people<<人:位置=> {:标题=> 行政助理}
 

我已经超载的<<运营商在我的has_many:通过声明,如下所示:

 的has_many:人:通过=> :岗位做
  DEF<< * ARGS
    ARG = args.first
    如果arg.is_a?(人)
      self.push([阿根廷])
    ELSIF arg.is_a?(散)
      #不知道做什么,在这里(见下文)
    其他
      提高无效值#有一个更好的错误,以提高在这里,但现在不够好。
    结束
  结束
结束
 

得到这个工作的好处是,它运作良好语法,并允许我简要地分配数据的连接对象(位置),同时添加的人到Directory对象的人收藏。

但我不能让它工作,因为我需要能够访问目录对象,对左侧的人收藏的<<运营商是一个属性,以便建立一个位置,并将其保存到数据库中。

所以,我的问题是:

  1. 有没有办法从一个对象的属性访问对象?
  2. 在备选方案中,有另一种方式过载的<<运营商这样同时增加一个对象到集合,我可以很容易地将数据分配到加盟模式?

非常感谢您的帮助和周到的反应。我一直在走黑客在这半天都没有结果。

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

 模块AddToPeopleAndPositionExtension
  DEF<< * ARGS
    ARG = args.first
      如果arg.is_a?(人)
        self.push([阿根廷])
        回归自我
      ELSIF arg.is_a?(散)
        目录= proxy_association.owner
        人= ARG [:人]
        位置= person.positions.build(:directory_id => directory.id,:标题=> ARG [:位置] [:标题])
        position.save
      其他
        提高无效值
      结束
  结束
结束

类目录<的ActiveRecord :: Base的
  #关系
  的has_many:位置
  的has_many:人:通过=> :位置,:延长=> AddToPeopleAndPositionExtension
结束
 

这让我叫的<<运营商如果我不关心发生在加盟模式是什么,像标准的方式:

 目录= Directory.last#假设检索目录对象
人= Person.last#假设检索一个Person对象
directory.people<<人
 

和,我还可以把它在指定像连接模型的属性的方式:

 目录= Directory.last#假设检索目录对象
人= Person.last#假设检索一个Person对象
directory.people<< {:人=>人:位置=> {:标题=> 行政助理}}
 

解决方案

您可以使用 proxy_association 帮手块内拿到联想和 proxy_association.owner 来获得Directory对象本身。请参阅<一href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Association+extensions">here对于这方面的一些详细信息。

I have three classes: Person, Position, and Directory.

  • A Person has_many :directories, :through => :position.
  • A Directory has_many :people, :through => :position.
  • Both Person and Directory has_many :positions.
  • The Position model, in addition to having an id, a person_id, and a directory_id, has one or more additional fields (e.g., title).

What I would like to be able to do is add data to the join model, such as the title field, every time I add a person to a Directory.people collection. The usual << operator won't cut it. 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

This will add a person to the people collection of a Directory object, but will not allow me the chance to assign data to the join model. So, after doing a lot of research on this site, I found another way to add the Person to the people collection and add data to the Position that links the Person and the Directory, 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

This is cumbersome. An equally cumbersome way would be:

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")

Again, seems wrong because I'd like to be able to emphasize the relationship between Person and Directory, which I believe is what makes using has_many :through appropriate.

What I'd like to be able to do is use the << operator, and just pass the additional data, e.g.:

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"}

I have overloaded the << operator in my has_many :through declaration, as follows:

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

The advantage of getting this working is that it works well syntactically, and allows me to concisely assign data to the join object (a Position) while adding the Person to the people collection of the Directory object.

But I cannot make it work because I would need to be able to access the Directory object of which the people collection on the left side of the << operator is an attribute, in order to build a Position and save it to the database.

So, my questions are:

  1. Is there a way to access an object from an attribute of an object?
  2. In the alternative, is there another way to overload the << operator so that I can easily assign data to the join model while adding one object to a collection?

Thanks very much for your help and thoughtful responses. I've been hacking away at this for half a day to no avail.

Answer Thanks to PinnyM, who answered this question, I was able to come up with this implementation:

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

This allowed me to call the << operator in the standard way if I did not care what happens on the join model, like:

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

And, I could also call it in a way that specified attributes of the join model like:

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"}}

解决方案

You can use the proxy_association helper inside the block to get the association and proxy_association.owner to get the Directory object itself. See here for some more info on this.

这篇关于覆盖的ActiveRecord&LT;&LT;运营商的的has_many:通过关系,以接受连接模型数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆