2010-02-17 6 views
1

Je suis tenté de dire oui.Polymorphe has_many à travers les contrôleurs: Antipattern?

Un exemple artificiel, en utilisant has_many: à travers et polymorphes:

class Person < ActiveRecord::Base 
    has_many :clubs, :through => :memberships 
    has_many :gyms, :through => :memberships 
end 

class Membership < ActiveRecord::Base 
    belongs_to :member, :polymorphic => true 
end 

class Club < ActiveRecord::Base 
    has_many :people, :through => :memberships 
    has_many :memberships, :as => :member 
end 

etc. 

En laissant de côté, pour le moment, la question de savoir si une salle de gymnastique est un club, ou tout autre des défauts de conception.

Pour ajouter un utilisateur à un club, il est tentant d'être RESTful et POST un person_id et un club_id à MembersController, comme ceci:

form_for club_members_path(@club, :person_id => person.id) ... 

Dans ce scénario, quand nous décidons de le faire:

form_for gym_members_path(@gym, :person_id => person.id) ... 

Nous aurions besoin de faire en sorte que MembersController décide si la ressource parente est un club ou un gymnase, et agir en conséquence. Une solution non-DRY:

class MembersController < ApplicationController 
    before_filter :find_parent 
    ... 
    private 
    def find_parent 
    @parent = Gym.find(params[:gym_id]) if params[:gym_id] 
    @parent = Club.find(params[:club_id]) if params[:club_id] 
    end 
end 

Choquant horriblement si vous le faites plus d'une fois.

En outre, cela repose sur le concept selon lequel rejoindre un club et rejoindre un gymnase sont à peu près les mêmes. Ou au moins, Gym # add_member et Club # add_member se comporteront de manière plus ou moins parallèle. Mais nous devons supposer que les gymnases et les clubs peuvent avoir différentes raisons de rejeter une demande d'adhésion. MembersController devrait gérer les messages flash et les redirections pour deux ou plusieurs états d'erreur.

Il existe des solutions dans la nature. ResourceController génial de James Golick a une façon de traiter parent_type, parent_object, etc. Revolution On Rails a une bonne solution pour DRYing up multiple polymorphic controllers en ajoutant des méthodes à ApplicationController. Et bien sûr, ActionController a #polymorhpic_url pour des cas plus simples comme Blog # messages et Article # messages, etc

Tout cela me laisse me demander, est-ce vraiment utile de mettre toute cette pression sur MembersController du tout? Le polymorphisme est assez bien géré dans Rails, mais mon sentiment est que l'utilisation de conditions (if/unless/case) est une indication claire que vous ne savez pas de quel type vous avez affaire. La métaprogrammation aide, mais seulement quand les types ont un comportement similaire. Les deux semblent indiquer la nécessité d'une révision de la conception.

J'aimerais avoir votre avis à ce sujet. Est-il préférable d'être SEC dans ce scénario, ou de savoir exactement quel type de parent vous avez? Suis-je névrosé ici?

+0

J'ai une situation similaire où j'ai environ 25 différents polymorphes suspendus sur une table de structure arborescente centrale. Dans mes contrôleurs pour chaque polymorphe je traite la ressource par son nom (par exemple @page, @link etc ...) J'ai toujours besoin de trouver le parent de cette ressource (qui est résolu en passant par cette variable à la table de l'arbre et en regardant le parent là-bas) mais comme le nom est toujours différent, je ne connais pas une façon facile/propre de le faire. –

Répondre

Questions connexes