2012-01-20 6 views
2

J'ai un modèle d'amitié d'utilisateur que je veux écrire une recherche pourRelation inverse dans la table de jointure

est une relation habtm appelée pairs, reliant 2 utilisateurs ensemble. Une relation est une connexion unique (Joe < -> Steve, pas Joe -> Steve et Steve -> Joe).

Mon table de jointure est la suivante: user_id peer_id

deux stocker un ID utilisateur dans la relation. Voici le HABTM sur l'utilisateur.

has_and_belongs_to_many :peers, class_name: 'User', 
foreign_key: 'user_id', association_foreign_key: 'peer_id', 
join_table: 'users_peers' 

J'essaie de comprendre le viseur sql qui permettra cet enregistrement dans la table de jointure pour montrer les deux côtés. id_utilisateur = steve.id pair_id = joe.id

pour afficher les relations lorsque j'appelle joe.peers et steve.peers. Actuellement, steve.peers renvoie joe, mais joe.peers ne montre rien.

+0

voir connexe: http://dba.stackexchange.com/questions/10199/how-should-i-design-a-relationship-table-for-friendship – klochner

Répondre

2

En règle générale, les relations s'expriment le mieux d'une manière ou d'une paire de relations unidirectionnelles. En effet, dans la plupart des bases de données relationnelles, il est facile d'établir une relation A vers B ou B vers A, mais pas les deux avec un seul enregistrement. Vous avez essentiellement besoin de deux requêtes, sauf si vous faites beaucoup de suppositions et pirater. Dans mon expérience, l'utilisation de has_and_belongs_to_many ne va pas vous faciliter la vie, car c'est une relique de Rails 1.0 qui n'est pas aussi bonne que la méthode has_many :through qui l'a remplacée. Dans votre cas, voici comment cela jouer:

class Node < ActiveRecord::Base 
    has_many :peers_of, 
    :class_name => 'Peer', 
    :foreign_key => :of_user_id 

    has_many :peers_to, 
    :class_name => 'Peer', 
    :foreign_key => :to_user_id 

    has_many :peers, 
    :through => :peers_of, 
    :source => :to_user 

    has_many :peers_with, 
    :through => :peers_to, 
    :source => :of_user 
end 

class Peer < ActiveRecord::Base 
    belongs_to :of_user, 
    :class_name => 'User' 
    belongs_to :to_user, 
    :class_name => 'User' 
end 

La sémantique obtenir un peu en désordre, de sorte que vous aurez probablement envie de les ajuster. L'idée ici est d'établir une relation bidirectionnelle lors de l'ajout d'un "pair", où il s'agit d'une paire d'enregistrements A-> B et B-> A. Pour les besoins de l'interrogation, vous ne récupérerez, par exemple, que @user.peers et ne devrez pas vous inquiéter de la relation inverse peers_with car cela devrait produire des résultats identiques si vous avez maintenu l'intégrité des données.

+0

Merci, je vais donne un coup d'oeil. J'espérais juste un peu de magie :) - Les relations autoréférentielles bidirectionnelles me font un peu mal à l'esprit ... – Jared

+0

Il est plus facile d'écrire une tâche pour valider et réparer les relations si l'une des paires est manquante qu'elle ne l'est comprendre comment faire de la relation unidirectionnelle une fonction bidirectionnelle. – tadman

1

Vous pouvez simplement écrire le sql à la main:

class PeerRelation 
    belongs_to :user1, :class_name=>"User" 
    belongs_to :user2, :class_name=>"User" 
end 

class User 

    def set_peer(user) 
    user1_id, user2_id = [self.id, user.id].sort 
    PeerRelation.find_or_create_by_user1_id_and_user2_id(user1_id, user2_id) 
    end 

    def peers 
    User.joins("inner join peer_relations on 
        peer_relations.user1_id = #{self.id} or 
        peer_relations.user2_id = #{self.id}") 

    end 
end 

Mais l'approche de Tadman est plus intelligent d'un point de vue de l'intégrité des données, et est plus conforme à ce que DBA vous dira. (Voir mon commentaire à votre question)

+0

Vous pouvez également implémenter cela comme une définition 'finder_sql' sur la relation, mais faire un' JOIN' avec un 'OR' dans la base de données fait pleurer la plupart des bases de données si la table est grande. – tadman

+0

ne savait pas cela - merci pour le pourboire – klochner

Questions connexes