1

Ich bin implementieren das System, mit dem Benutzer folgen können "Followable" (in meinem Fall diese können ein Ereignis, Ort oder andere Benutzer sein).Viele zu viele mit polymorphe Zuordnung funktioniert nicht in beiden Richtungen

Meine Idee:

Folgen Modell (Join-Tabelle) die user_id, verfolgbare Art und followale_id hält

class Follow < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :followable, polymorphic: true 
end 

Ereignis

class Event < ActiveRecord::Base  
    has_many :follows, as: :followable 
    has_many :users, through: :follows 
end 

Platz

class Place < ActiveRecord::Base 
    has_many :follows, as: :followable 
    has_many :users, through: :follows  
end 

Benutzer

class User < ActiveRecord::Base 
    has_many :follows 
    has_many :events, through: :follows, source: :followable, source_type: "Event" 
    has_many :places, through: :follows, source: :followable, source_type: "Place" 
    has_many :users, through: :follows, source: :followable, source_type: "User" 
end 

Das Problem ist, dass die real nur in eine Richtung funktioniert, ich tun kann:

user.follows.create(followable:event1) #follow event1 
user.follows.create(followable:place1) #follow place1 
user.follows.create(followable:user1) #follow user1 
user.follows # displays all following relations user has established 

Aber ich kann nicht tun:

event1.follows #return follow objects(some user - event1 pairs) 
event1.users #return all of the users that follow this event 
user1.users #return all of the users that user1 follows, the most confusing part.. 

Alle oben genannten Werte sind null.

Wie soll ich die Beziehungen herstellen, damit es in beide Richtungen funktioniert?
Außerdem würde ich gerne einige Bemerkungen darüber hören, wie ich diese Idee verbessern kann, weil es das erste Mal ist, dass ich mit komplexeren Realitäten herumspiele. Vielen Dank im Voraus.

+0

Kurzübersicht: Sind Sie sicher, dass Sie keinen veralteten Cache von 'event1.follows' sehen? Was passiert, wenn Sie "event1.follows (true)" versuchen? (Das "true" hier weist ActiveRecord an, die Assoziation neu zu laden, anstatt ihren Cache zu verwenden, wenn sie es hat) –

+0

Ausgabe: # Wojciech

+0

Was ist mit 'event1.follows.to_sql'? –

Antwort

1

Fangen sich mit dem User-Modell als der heikelste beginnen:

class User < ActiveRecord::Base 
    has_many :follows, source: :user 
    has_many :follows_as_fallowable, 
        class_name: 'Follow', 
        as: :followable 

    has_many :followers, through: :follows_as_fallowable, 
         source: :user 

    # other users the user is following      
    has_many :followed_users, through: :follows, 
          source: :followable, 
          source_type: 'User' 
end 

Hinweis, die wir brauchen zwei verschiedene Beziehungen zu follows aufgrund der Tatsache, dass der Benutzer in jeder Spalte je nach sein kann, wenn der Benutzer der Anhänger oder das Objekt, dem gefolgt wird.

können wir jetzt tun, einen einfachen Test zu überprüfen, ob die Beziehung korrekt eingerichtet ist:

joe = User.create(name: 'Joe') 
jill = User.create(name: 'Jill') 
joe.followers << jill 
jill.followed_users.include?(joe) # true 
joe.followers.include?(jill) # true 

Um dann einen Setup der bidirektionale Beziehung zwischen Benutzer und einem verfolgbaren Modell würden Sie tun:

class Event < ActiveRecord::Base 
    has_many :follows, as: :followable 
    has_many :followers, through: :follows, 
         source: :user 
end 

class User < ActiveRecord::Base 
    # ... 
    has_many :followed_events, through: :follows, 
          source: :followable, 
          source_type: 'Event' 
end 

die Beziehungen in dem gefolgten Modell (Ereignis) sind so ziemlich das gleiche in jedem Modell, so dass Sie leicht zu einem Modul zur Wiederverwendung extrahieren können:

# app/models/concerns/followable.rb 
module Followable 
    extend ActiveSupport::Concern 

    included do 
    has_many :follows, as: :followable 
    has_many :followers, through: :follows, 
         source: :user 
    end 
end 

class Event < ActiceRecord::Base 
    include Followable 
end 

class Place < ActiceRecord::Base 
    include Followable 
end 
+0

Vielen Dank, es funktioniert perfekt, aber ein Problem mit dem Verständnis einer Sache: 'has_many: Anhänger, durch:: following_as_fallowable, Quelle:: user' Woher wissen Rails aus welcher Tabelle zu wählen? Es wird nicht basierend auf dem Assoziationsnamen abgeleitet, es wird nicht vom Argument class_name übernommen. Also woher weiß es, dass es Benutzerdatensatz zurückgeben sollte? – Wojciech

+0

'source:: user' sagt ihm, dass er die' belongs_to: user' Relation on Folly erhalten soll, die nicht polymorph ist. – max