2010-06-13 6 views
2

J'essaie de ranger mon code en utilisant named_scopes dans Rails 2.3.x mais où je suis aux prises avec les associations has_many: through. Je me demande si je mets les scopes au mauvais endroit ...Rails named_scope sur plusieurs tables

Voici un pseudo code ci-dessous. Le problème est que: la portée nommée acceptée est répliquée deux fois ... Je pourrais bien sûr appeler: accepter quelque chose de différent mais ce sont les statuts sur la table et il semble erroné de les appeler quelque chose de différent. Quelqu'un peut-il faire la lumière sur si je fais ce qui suit correctement ou non?

Je sais que Rails 3 est sorti, mais il est toujours en version bêta et c'est un gros projet que je fais, donc je ne peux pas encore l'utiliser en production.

class Person < ActiveRecord::Base 
    has_many :connections 
    has_many :contacts, :through => :connections 

    named_scope :accepted, :conditions => ["connections.status = ?", Connection::ACCEPTED] 
    # the :accepted named_scope is duplicated 
    named_scope :accepted, :conditions => ["memberships.status = ?", Membership::ACCEPTED] 
end 

class Group < ActiveRecord::Base 
    has_many :memberships 
    has_many :members, :through => :memberships 
end 

class Connection < ActiveRecord::Base 
    belongs_to :person 
    belongs_to :contact, :class_name => "Person", :foreign_key => "contact_id" 
end 

class Membership < ActiveRecord::Base 
    belongs_to :person 
    belongs_to :group 
end 

Je suis en train de lancer quelque chose comme person.contacts.accepted et group.members.accepted qui sont deux choses différentes. Les named_scopes ne devraient-ils pas être dans les classes Membership et Connection?

Cependant, si vous essayez de placer les étendues nommées dans les classes Membership et Connection, vous obtenez cette erreur (car Person.find (2) .contacts renvoie un tableau de Personnes qui n'a pas de méthode 'accepted':

>> Person.find(2).contacts.accepted 
NoMethodError: undefined method `accepted' for #<Class:0x108641f28> 

Une solution est de simplement appeler les deux différents quelque chose de portée du nom différent dans la classe de personne ou même de créer des associations distinctes (c.-à-has_many:. accepted_members et has_many: accepted_contacts) mais il semble hackish et en réalité, j'ai beaucoup plus que simplement accepté (membres bannis, connexions ignorées, en attente, demandé, etc.)

Répondre

0

Vous avez répondu à votre propre question:

Shouldn't the named_scopes be in the Membership and Connection classes?

Oui, ils devraient être. Cela vous permettra de les appeler comme vous le souhaitez. C'est aussi logiquement où ils appartiennent.

Si vous voulez quelque chose sur la personne qui vérifie les deux, vous pouvez faire quelque chose comme:

named_scope :accepted, :conditions => ["connections.status = ? OR memberships.status = ?", Connection::ACCEPTED, Membership::ACCEPTED]

Peut-être que vous voulez que ce soit un ET? pas certain.

+0

Non cela ne fonctionne pas - Vous obtenez une erreur - J'ai mis à jour ma question pour montrer ce qu'est l'erreur. >> Person.find (2) .contacts.accepté NoMethodError: méthode indéfinie 'accepted 'pour # wakiki

+0

et si vous mettez les deux étendues en un comme dans votre deuxième suggestion, vous obtenez une erreur de colonne inconnue: >> Person.find (2) .contacts.accepté ActiveRecord :: StatementInvalid: Mysql :: Erreur: Colonne inconnue 'memberships.status' dans 'clause where': SELECT SQL_NO_CACHE 'people'. * FROM' people' INNER JOIN 'connections' SUR' people'.id = 'connections'.contact_id WHERE ((' connections'.person_id = 2)) ET ((connections.status = 0 OR memberships.status = 0) ET (('connections'. person_id = 2))) – wakiki

+0

Il vous manque l'association de la personne à l'appartenance. L'adhésion appartient à une personne, mais la personne n'a pas ou n'a pas beaucoup d'adhésions. Vous pouvez également avoir besoin d'utiliser ': joins' dans la portée nommée pour le faire fonctionner. Ce que vous voulez faire est définitivement possible. – x1a4

0

Je suis sûr que ce n'est pas la meilleure façon et je crois que vous pouvez le faire sur person et group modèles, mais je crois aussi ce qui suit travaillera pour vous:

# models 
class Person < ActiveRecord::Base 
    has_many :connections 
    has_many :contacts, :through => :connections 

    has_many :memberships 
    has_many :groups, :through => :memberships 
end 

class Group < ActiveRecord::Base 
    has_many :memberships 
    has_many :members, :through => :memberships 
end 

class Connection < ActiveRecord::Base 
    belongs_to :person 
    belongs_to :contact, :class_name => "Person", :foreign_key => "contact_id" 

    named_scope :accepted, :conditions => ["status = ?", Connection::ACCEPTED] 
end 

class Membership < ActiveRecord::Base 
    belongs_to :person 
    belongs_to :group 

    named_scope :accepted, :conditions => ["status = ?", Membership::ACCEPTED] 
end 

# controller 
# get person's accepted contacts 
@person = Person.first 
@person.connections.accepted.map(&:contact) 

# get group's accepted members 
@group = Group.first 
@group.memberships.accepted.map(&:person) 
Questions connexes