はいと言いたくなる。
has_many :through と polymorphs を使用した不自然な例:
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.
とりあえず、ジムがクラブなのか、それとも他の設計上の欠陥なのかという問題はさておき。
User を Club に追加するには、次のように RESTful にして person_id と club_id を MemberController に POST するのが魅力的です。
form_for club_members_path(@club, :person_id => person.id) ...
このシナリオでは、次のことを行うことにしました。
form_for gym_members_path(@gym, :person_id => person.id) ...
親リソースがクラブかジムかを MemberController に判断させ、それに応じて動作させる必要があります。非 DRY ソリューションの 1 つ:
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
何度もやると驚くほどひどい。
また、クラブに入会することとジムに入会することはほぼ同じであるという概念に基づいています。または、少なくとも、Gym#add_member と Club#add_member は多かれ少なかれ並行して動作します。ただし、ジムとクラブでは、メンバーシップの申し込みを拒否する理由が異なる可能性があると想定する必要があります。MembersController は、2 つ以上のエラー状態のフラッシュ メッセージとリダイレクトを処理する必要があります。
世の中には解決策があります。James Golick の素晴らしい ResourceController には、parent_type、parent_object などを処理する方法があります。Revolution On Rails には、ApplicationController にいくつかのメソッドを追加することで、複数のポリモーフィック コントローラーを DRY するための優れたソリューションがあります。もちろん、ActionController には、Blog#posts や Article#posts などの単純なケース用の #polymorhpic_url があります。
これはすべて、MembersControllerにすべての圧力をかける価値があるのでしょうか? Rails ではポリモーフィズムはかなりうまく処理されますが、条件 (if/unless/case) を使用すると、どの型を扱っているかがわからないことが明確に示されているように感じます。メタプログラミングは役に立ちますが、型が同様の動作をする場合に限られます。どちらもデザインレビューの必要性を指摘しているようです。
これについてあなたの考えを聞きたいです。このシナリオでは DRY である方が良いですか、それとも自分の親のタイプを正確に知る方が良いですか? ここで私は神経症ですか?