开发者

Polymorphic has_many through Controllers: Antipattern?

开发者 https://www.devze.com 2022-12-20 06:48 出处:网络
I\'m tempted to say yes. A contrived example, using has_many :through and polymorphs: class Person < ActiveRecord::Base

I'm tempted to say yes.

A contrived example, using has_many :through and 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.

Leaving aside, for the moment, the question of whether a Gym is a Club, or any other design flaws.

To add a User to a Club, it's tempting to be RESTful and POST a person_id and a club_id to MembersController, like so:

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

In this scenario, when we decide to do:

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

We would need to make MembersController decide whether the parent resource is a Club or a Gym, and act accordingly. One non-DRY solution:

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

Shockingly awful if you do it more than once.

Also, it's predicated on the concept that joining a Club and joining a Gym are roughly the same. Or at least, Gym#add_member and Club#add_member will behave in a more or less parallel manner. But we have to assume that Gyms and Clubs might have different reasons for rejecting an application for membership. MembersController would need to handle flash messages and redirects for two or more error states.

There are solutions in the wild. James Golick's awesome ResourceController has a way of dealing with parent_type, parent_object, etc. Revolution On Rails has a nice solution for DRYing up multiple polymorphic controllers by adding some methods to ApplicationController. And of course, ActionController has #polymorhpic_url for simpler cases like Blog#posts and Article#posts, etc.

All this leaves me wondering, is it really worth putting all that pressure on MembersController at all? Polymorphism is handled pretty well in Rails, but my feeling is that using conditionals (if/unless/case) is a clear in开发者_Go百科dication that you don't know what type you're dealing with. Metaprogramming helps, but only when the types have similar behavior. Both seem to point to the need for a design review.

I'd love to hear your thoughts on this. Is it better to be DRY in this scenario, or to know exactly what parent type you have? Am I being neurotic here?

0

精彩评论

暂无评论...
验证码 换一张
取 消