1

Я хотел бы создать отношение самореференции в рельсах. У меня есть модель Person, и у человека должны быть мастера и ученики с одним и тем же объектом Person.Использование полиморфного отношения «многие-ко-многим» с привязкой к атрибутам относительно отношения в рельсах

До сих пор я пытался:

class Person <ActiveRecord::Base 
    has_many :relationships, :dependent => :destroy 
    has_many :masters, :through => :relationships, :conditions => "status='master'" 
    has_many :pupils, :through => :relationships, :conditions => "status='pupil'" 
    has_many :inverse_relationships, :class_name => "Relationship", 
     :foreign_key => "related_id" 
    has_many :inverse_masters, :through => :inverse_relationships, 
     :source => :person, :conditions => "status='master'" 
    has_many :inverse_pupils, :through => :inverse_relationships, 
     :source => :person, :conditions => "status='pupil'" 
end 

class Relationship < ActiveRecord::Base 
    belongs_to :person 
    belongs_to :master, :class_name => "Person", :foreign_key => 'related_id' 
    belongs_to :pupil, :class_name => "Person", :foreign_key => 'related_id' 
end 

Это похоже на работу, когда я пытаюсь выбрать:

@a = Person.find(:first) 
@a.masters 

, но когда я пытаюсь сделать толчок в мастера, он сохраняет отношения без статус установлен на мастер. Вместо этого он сохраняет нуль. Есть ли простой способ сэкономить status=master, когда я нажимаю на мастеров и status=pupil, когда я нажимаю учеников?

Благодаря

ответ

2

Чтобы сделать его коротким решение: объединение обратных вызовов (более здесь в рамках секции Ассоциации Callback: http://railsapi.com/doc/rails-v3.0.0/classes/ActiveRecord/Associations/ClassMethods.html)

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

class Person < ActiveRecord::Base 
    has_many :relationships 
    has_many :pupils, :through => :relationships, :source => :other_person, :conditions => 'relationships.type = "MasterPupil"', :after_add => Proc.new{|p,o| Relationship.update_all("type = 'MasterPupil'", ['person_id = ? AND other_person_id = ?', p.id, o.id])} 
    has_many :masters, :through => :relationships, :source => :other_person, :conditions => 'relationships.type = "PupilMaster"', :after_add => Proc.new{|p,o| Relationship.update_all("type = 'PupilMaster'", ['person_id = ? AND other_person_id = ?', p.id, o.id])} 
end 

class Relationship < ActiveRecord::Base 
    belongs_to :person 
    belongs_to :other_person, :class_name => 'Person' 
    before_validation :set_type 

    def set_type 
    self.type = 'OpenRelationship' 
    end 
end 

class MasterPupil < Relationship 
end 

class PupilMaster < Relationship 
end 

модель Relationship содержит столбец типа, который является эквивалентом столбце состояния, но тип лучше, если я потом хочу сделать ИППП d объявите модели отношений MasterPupil/PupilMaster.

Relationship также имеет set_type before_validation, который установит тип в открытые отношения, которые должны быть временными до after_add обратного вызова, определенной в модели Person в каждой ассоциации будет устанавливать вещи четкие (и устанавливать либо MasterPupil или тип PupilMaster)

и теперь:

Loading development environment (Rails 3.0.0) 
irb(main):001:0> p = Person.create 
=> #<Person id: 1, created_at: "2010-09-10 23:35:37", updated_at: "2010-09-10 23:35:37"> 
irb(main):002:0> p.pupils 
=> [] 
irb(main):003:0> p.masters 
=> [] 
irb(main):004:0> p.pupils << Person.create 
=> [#<Person id: 2, created_at: "2010-09-10 23:35:56", updated_at: "2010-09-10 23:35:56">] 
irb(main):005:0> Relationship.all 
=> [#<MasterPupil id: 1, person_id: 1, other_person_id: 2, type: "MasterPupil">] 
irb(main):006:0> p.masters << Person.create 
=> [#<Person id: 3, created_at: "2010-09-10 23:36:29", updated_at: "2010-09-10 23:36:29">] 
irb(main):007:0> Relationship.all 
=> [#<MasterPupil id: 1, person_id: 1, other_person_id: 2, type: "MasterPupil">, #<PupilMaster id: 2, person_id: 1, other_person_id: 3, type: "PupilMaster">] 
irb(main):008:0> p.reload 
=> #<Person id: 1, created_at: "2010-09-10 23:35:37", updated_at: "2010-09-10 23:35:37"> 
irb(main):009:0> p.pupils 
=> [#<Person id: 2, created_at: "2010-09-10 23:35:56", updated_at: "2010-09-10 23:35:56">] 
irb(main):010:0> p.masters 
=> [#<Person id: 3, created_at: "2010-09-10 23:36:29", updated_at: "2010-09-10 23:36:29">] 
+0

Это то, что я думал, мне понадобятся рельсы 3. Как обратно совместима r3? Хотя я, вероятно, не могу ничего потерять с хорошей резервной копией;) Я пробовал это решение, но у меня есть 2.3.8, и он еще не имеет обратных вызовов ассоциации. Я проверил valid_keywords в источнике для этого;) Спасибо, человек, я вернусь к этому завтра, но я думаю, что это прекрасно, поскольку я попробовал, только версия не соответствовала. – Tamisoft

+0

Хорошо, похоже, что он отлично работает на 2.3.8, хотя некоторые говорили на форумах, что у него могут быть ошибки, но пока я все настроен. Большое спасибо за помощь. – Tamisoft

+0

проблем нет. просто проголосовать за мой ответ, и это будет здорово :) – hellvinz