8

में एकाधिक सेल्फ-जॉइन के साथ कई से अधिक सहयोग मैं स्वयं-जुड़ने के माध्यम से उसी मॉडल के रिकॉर्ड के बीच कई संबंधों को लागू करने की कोशिश कर रहा हूं (@Shtééf's answer पर आधारित)। मेरे पास निम्नलिखित मॉडल हैंActiveRecord

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 

इस सेटअप के साथ मैं प्रत्येक रिकॉर्ड के लिए अधीनस्थों और प्रबंधकों की सूचियों को सफलतापूर्वक एक्सेस कर सकता हूं। हालांकि, मैं निम्नलिखित तरीके

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

समस्या यह संबंधों के प्रकार निर्धारित नहीं करता है वह यह है कि में संबंध बनाने के लिए आती है, तो मैं लिखने के लिए

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

मैं कुछ गलत कर रहा हूँ है?

उत्तर

8

आप has_many संघ पर before_add और before_remove कॉलबैक का उपयोग कर सकते हैं:

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
आप
इसके अलावा कॉलबैक में create की build instread उपयोग कर सकते हैं सक्षम बनाना चाहिए आप इस समाधान के बारे में this question पढ़ सकते हैं

3

कई से अधिक सेल्फ-जॉइन एसोसिएशन बनाने के लिए, मैं अनुशंसा करता हूं कि कनेक्शन को प्रबंधित करने के लिए कई तालिकाओं को और अधिक समझदारी हो सकती है। इस तरह यह डेटा स्टैंडपॉइंट से बिल्कुल स्पष्ट है कि वास्तव में क्या हो रहा है, और यह एक तर्क दृष्टिकोण से भी स्पष्ट है। तो इन पंक्तियों के साथ कुछ:

create_table :manage_relation do |t| 
    t.references :employee_id 
    t.references :manager_id 
end 
create_table :subordinate_relation do |t| 
    t.references :employee_id 
    t.references :subordinate_id 
end 

class Employee < ActiveRecord::Base 

    has_many :subordinates, 
      :through => :subordinate_relation, 
      :class_name => "Employee", 
      :foreign_key => "subordinate_id" 
    has_many :managers, 
      :through => :manage_relation, 
      :class_name => "Employee", 
      :foreign_key => "manager_id" 

    belongs_to :employee, 
      :class_name => "Employee" 
end 

इस तरह यह एक कोडन दृष्टिकोण से आवश्यक से किसी भी अधिक जटिल नहीं मिलता है, और आप मानक संग्रह का उपयोग कर उस तक पहुँच सकते हैं और यह उचित रूप से बिना आप के लिए अपने कनेक्शन स्थापित करेगा आप उन्हें प्रबंधित करना है। तो, इन संग्रहों के दोनों काम करना चाहिए ..

employee.managers 
employee.subordinates 

और आप किसी भी अन्य चर प्रबंधन करने के लिए नहीं कर सका। सही बात? यह एक टेबल जोड़ता है, लेकिन स्पष्टता में सुधार करता है।

+0

और मैं पूरी तरह से निश्चित नहीं हूं कि संबंधित_ आवश्यक है, लेकिन मेरे पास टी सेट करने का समय नहीं था वह मेरे स्थानीय स्थापित पर पूरा अभ्यास। आप इसे बिना और बिना देख सकते हैं और देख सकते हैं कि आपको किस प्रकार के परिणाम मिलते हैं। –

+1

इसके अलावा, अगर आप इस मार्ग पर जाना पसंद करते हैं, तो आपको यह प्रश्न देखना चाहिए। यह आपके द्वारा किए जा रहे कार्यों के आधार पर और दिखाता है, हालांकि मुझे अभी भी कम कमी होने की स्पष्टता मिलती है (fyi- प्रश्न में प्रश्न का उत्तर दिया गया है): http://stackoverflow.com/questions/6426383/rails- एसोसिएशन-डेटा-ऑन-द-एसोसिएशन-टेबल –

2

इस प्रकार मैं अपने मॉडल को फिर से करना होगा:

class ManagerRelation < ActiveRecord::Base 
    belongs_to :manager, :class_name => 'Employee' 
    belongs_to :subordinate, :class_name => 'Employee' 
end 

class Employee < ActiveRecord::Base 
    has_many :manager_relations,  :class_name => "ManagerRelation", 
       :foreign_key => :subordinate_id 
    has_many :subordinate_relations, :class_name => "ManagerRelation", 
       :foreign_key => :manager_id 

    has_many :managers,  :source => :manager,  
       :through => :manager_relations 

    has_many :subordinates, :source => :subordinate, 
       :through => :subordinate_relations 
end 

अब आप कर सकते हैं निम्नलिखित:

employee.managers 
employee.subordinates  
employee.managers << employee2  
employee.subordinates << employee3 

नोट: यह आमतौर पर एक कंपनी जब वे छोड़ने के लिए के लिए एक संकेत है दो प्रबंधकों को रिपोर्ट करने के लिए बनाया जाता है :-)

+0

आपके उत्तर के लिए धन्यवाद। मैं प्रत्येक संबंध प्रकार के लिए अतिरिक्त तालिकाओं से बचने की कोशिश कर रहा था, लेकिन शायद यह करने का सबसे अच्छा तरीका है। – Andrei

2

प्रस्तुत संबंध

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


class Employee < ActiveRecord::Base 

    has_many :subordinate_relations, :class_name => "Relation", :conditions => {:rel_type => 'manager of'}, :foreign_key => :employee_a 
    has_many :subordinates, :through => :subordinate_relations, :source => :subordinate, :foreign_key => :employee_b 

    has_many :manager_relations, :class_name => "Relation", :conditions => {:rel_type => 'manager of'}, :foreign_key => :employee_b 
    has_many :managers, :through => :manager_relations, :source => :manager, :foreign_key => :employee_a 

end 


class Relation < ActiveRecord::Base 

    belongs_to :manager, :class_name => "Employee", :foreign_key => :employee_a 
    belongs_to :subordinate, :class_name => "Employee", :foreign_key => :employee_b 

end 


e = Employee.create 
e.subordinates.create #Employee ... 
e.subordinates #[<Employee ...] 

e2 = Employee.create 
e2.managers.create #Employee 
e2.managers #[<Employee ...] 

हालांकि समाधान काम करता है - मैं "rel_type" के साथ एसोसिएशन को जोड़कर थोड़ा उलझन में हूं। इस मामले में - मैं कहेंगे rel_type अनावश्यक है और संबंध के रूप में निम्नानुसार मैप किया जाना चाहिए:

create_table :relations do |t| 
    t.reference :manager 
    t.reference :subordinate 
end 

ऐसे मामले में, संघ मानचित्रण एक बालक सरल होना चाहिए।