Полиморфный has_many через контроллеры: Antipattern?
Я испытываю желание сказать да.
Придуманный пример с использованием 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.
Оставляя в стороне вопрос о том, является ли тренажерный зал клубом, или какие-либо другие недостатки дизайна.
Чтобы добавить пользователя в клуб, заманчиво быть RESTful и POST person_id и club_id в MembersController, например:
form_for club_members_path(@club, :person_id => person.id) ...
В этом сценарии, когда мы решили сделать:
form_for gym_members_path(@gym, :person_id => person.id) ...
Нам нужно будет заставить MembersController решить, является ли родительский ресурс клубом или спортзалом, и действовать соответствующим образом. Одно неСУХОЕ решение:
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 должен обрабатывать флэш-сообщения и перенаправления для двух или более состояний ошибки.
Есть решения в дикой природе. У потрясающего ResourceController от Джеймса Голика есть способ работы с parent_type, parent_object и т. Д. Revolution On Rails предлагает отличное решение для СУШКИ нескольких полиморфных контроллеров путем добавления некоторых методов в ApplicationController. И, конечно же, ActionController имеет #polymorhpic_url для более простых случаев, таких как сообщения в блоге # статьи и сообщения в статье # и т. Д.
Все это заставляет меня задуматься: а стоит ли вообще оказывать такое давление на MembersController? Полиморфизм довольно хорошо обрабатывается в Rails, но я чувствую, что использование условных выражений (если / если / не случай) является четким признаком того, что вы не знаете, с каким типом вы имеете дело. Метапрограммирование помогает, но только когда типы имеют похожее поведение. Оба, кажется, указывают на необходимость пересмотра дизайна.
Я хотел бы услышать ваши мысли по этому поводу. Лучше быть СУХИМ в этом сценарии или точно знать, какой у вас родительский тип? Я здесь невротик?
1 ответ
Я думаю, что эта ссылка дает ответ на ваш вопрос http://revolutiononrails.blogspot.com/2007/05/drying-up-polymorphic-controllers.html