许多一对多多个协会自加盟的ActiveRecord [英] Many-to-many association with multiple self-joins in ActiveRecord

查看:130
本文介绍了许多一对多多个协会自加盟的ActiveRecord的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过实行同一型号的记录之间的多重关系自联接(基于<一href="http://stackoverflow.com/questions/2168442/many-to-many-relationship-with-the-same-model-in-rails/2168528#2168528">@Shtééf's回答)。我有以下型号

I am trying to implement multiple relations between records of the same model via self-joins (based on @Shtééf's answer). I have the following models

create_table :relations, force: true do |t|
  t.references :employee_a
  t.string     :rel_type
  t.references :employee_b
end

class Relation < ActiveRecord::Base
  belongs_to :employee_a, :class_name => 'Employee'
  belongs_to :employee_b, :class_name => 'Employee'
end

class Employee < ActiveRecord::Base
  has_many :relations, foreign_key: 'employee_a_id'
  has_many :reverse_relations, class_name: 'Relation', foreign_key: 'employee_b_id'

  has_many :subordinates, through: :relations, source: 'employee_b', conditions: {'relations.rel_type' => 'manager of'}
  has_many :managers, through: :reverse_relations, source: 'employee_a', conditions: {'relations.rel_type' => 'manager of'}
end

通过这个设置,我可以成功访问下属和经理的名单为每个记录。然而,我有困难创建以下列方式关系

With this setup I can successfully access the lists of subordinates and managers for each record. However, I have difficulties to create relations in the following way

e = Employee.create
e.subordinates.create
e.subordinates #=> []
e.managers.create
e.managers #=> []

现在的问题是,它并没有设置关系的类型,所以我必须写

The problem is that it does not set type of relations, so I have to write

e = Employee.create
s = Employee.create
e.relations.create employee_b: s, rel_type: 'manager of'
e.subordinates #=> [#<Employee id:...>]

我是不是做错了什么?

Am I doing something wrong?

推荐答案

您可以使用 before_add before_remove 回调上的has_many关联:

You can use before_add and before_remove callback on the has_many association :

class Employee < ActiveRecord::Base
  has_many :relations, foreign_key: 'employee_a_id'
  has_many :reverse_relations, class_name: 'Relation', foreign_key: 'employee_b_id'

  has_many :subordinates, 
           through: :relations, 
           source: 'employee_b', 
           conditions: {'relations.rel_type' => 'manager of'}
           :before_add => Proc.new { |employe,subordinate| employe.relations.create(employe_b: subordinate, rel_type: 'manager of') },
           :before_remove => Proc.new { |employe,subordinate| employe.relations.where(employe_b: subordinate, rel_type: 'manager of').first.destroy }

  has_many :managers,  
           through: :reverse_relations, 
           source: 'employee_a', 
           conditions: {'relations.rel_type' => 'manager of'}
           :before_add => Proc.new { |employe,manager| employe.reverse_relations.create(employe_a: manager, rel_type: 'manager of') },
           :before_remove => Proc.new { |employe,manager| employe.reverse_relations.where(employe_b: subordinate, rel_type: 'manager of').first.destroy }

这应该工作,使你能够使用 employe.managers.create
您可能需要使用构建 的instread创建回调
你也可以读<一href="http://stackoverflow.com/questions/5785930/rails-has-many-setter-should-set-conditions-if-specified">this这个解决的问题

This should works and make you able to use employe.managers.create
You may want to use build instread of create in the callback
Also you can read this question about this solution

这篇关于许多一对多多个协会自加盟的ActiveRecord的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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