Лучшая практика для обработки двух похожих объектов - PullRequest
2 голосов
/ 07 февраля 2010

Допустим, у меня есть два разных набора контроллера / вида, которые в основном идентичны.

Рабочее время и часы работы персонала

Первый содержит business_id, второй - staff_id. В противном случае они выглядят одинаково. id, mon_start_time, mon_stop_time, tues_start_time, tues_stop_time и т. д. ...

1) Есть ли способ, которым я бы использовал один и тот же контроллер для них, так как они так похожи? Кажется, в этом нет особого смысла, но я просто продолжаю думать о том, насколько они похожи и насколько много дублирующего кода.

2) Дополнительно для каждого у меня есть форма в частичном. Я пытаюсь использовать один и тот же для рабочего и рабочего времени. Частичное в наиболее упрощенном состоянии выглядит так:

-form_for (obj) do | f |
= f.error_messages %п = выберите obj.class,: mon_start_time, часы в = выберите obj.class,: mon_stop_time, часы

= link_to 'Back', obj_path

Итак, есть 3 уникальные вещи, которые мне нужно передать. Объект 'obj', business_hours или staff_hours. Это нормально в form_for, но как мне получить имя контроллера в нижнем регистре для первого параметра выбора? Мне нужны 'business_hour' и 'staff_hour' из 'obj'. Тогда мне нужно знать правильную ссылку «Назад».

Я знаю, что могу передавать параметры в партиал, но мне просто любопытно, есть ли более хитрый способ сделать это. Спасибо!

Ответы [ 4 ]

2 голосов
/ 07 февраля 2010

Дубликат кода имеет стоимость переноса, стоимость его обслуживания. Иногда мы не знаем, насколько высока эта стоимость, пока не проведем рефакторинг дубликата кода и не вздохнем с облегчением: теперь я могу изменить бизнес-правило в одном месте. Теперь я могу перестать печатать дважды.

Вы можете использовать два контроллера, но по-прежнему выполнять рефакторинг дубликата кода. Один из способов - поместить общий код в модуль, включенный в оба контроллера.

module CommonStuff

  def stuff_that_is_the_same
  end

end

controller FooController < ApplicationController

  include CommonStuff

  def stuff_that_is_different
    # Stuff specific to Foo
    stuff_that_is_the_same
    # More stuff specific to Foo
  end

end

controller BarController < ApplicationController

  include CommonStuff

  def stuff_that_is_different
    # Stuff specific to Bar
    stuff_that_is_the_same
    # More stuff specific to Bar
  end

end
2 голосов
/ 07 февраля 2010

Что касается получения имени контроллера, вы можете получить его в любом действии контроллера, вызвав метод

 controller_name

и состояние контроллера доступно в переменной экземпляра @controller для ваших представлений, поэтому, если вы хотите получить к нему доступ в своих представлениях, вы можете сделать

 @controller.controller_name

Теперь, глядя на ваши классы BusinessHours и StaffHours, я бы сказал, что лучше всего сделать их полиморфными. Первое, чего вы здесь добьетесь, это избавиться от практически идентичного стола. Так что проверь рельсы ядро ​​ полиморфные документы

ПРИМЕЧАНИЕ: Но has_many_polymorphs, упомянутый @amurmann, еще не доступен в ядре rails, хотя вы можете использовать его как плагин. Пратик написал в блоге об этом здесь

Для удаления дублирующего кода из контроллера вы можете либо поместить его в модуль (как сказал @Wayne), либо создать базовый контроллер, от которого ваши контроллеры рабочего времени и персонала унаследуют все общие функции. Теперь решение полностью зависит от того, что имеет больше смысла в вашем приложении. Лично я создам базовый контроллер, так как он больше ОО, сохраняю структурированные классы, и код не будет скрыт в каком-либо модуле. Но некоторые люди могут думать иначе.

0 голосов
/ 07 февраля 2010

Рассматривали ли вы Наследование в одной таблице ?Я думаю, что это лучшее решение для вас.

По сути, вы определяете таблицу и модель часов, которая выглядит точно так же, как часы персонала или рабочие часы, и содержит строковый столбец с именем type.Затем вы создаете подклассы часов, чтобы определить методы и проверки, относящиеся к рабочим и служебным часам соответственно.Вы также можете захотеть переопределить вашу ассоциацию на что-то более общее.В этом примере я назвал его хранителем, как и тот, кто хранит эти часы.

В двух словах: все функции полиморфизма для вас обрабатываются.

Модели:

class Hour < ActiveRecord::Base
  # common associations/methods etc go here
end

class BusinessHour < Hour
  belongs_to :keeper, :class_name => "Business"
  #business hour specific logic 
end

class StaffHour < Hour
  belongs_to :keeper, :class_name => "Staff"
  #staff hour specific logic
end

class Business < ActiveRecord::Base
  has_many :business_hours, :foreign_key => :keeper_id
  ...
end

class Staff < ActiveRecord::Base
  has_many :staff_hours, :foreign_key => :keeper_id
  ...
end

Маршрут:

map.resources :business_hours, :controller => "hours", :class => "BusinessHour"
map.resources :staff_hours, :controller => "hours", :class => "StaffHour"

Контроллер:

class HoursController < ApplicationController
  before_filter :select_class
  def select_class
    @class = Kernel.const_get(params[:class])
  end

  def new
    @hour = @class.new
    ...
  end

  def show 
    @hour = @class.find(params[:id])
    ...
  end

  ...
end

Представления будут выглядеть почти точно так же, как сейчас, но вы захотите, чтобы некоторые помощники сохранили выводпрямо.

module HourHelper
  def keeper_type
    @class == "BusinessHours" ? "Business" : "Staff"
  end     
end




-form_for(obj) do |f|
  =f.error_messages 
  %p =select keeper_type, :mon_start_time, hours 
    to 
    =select keeper_type, :mon_stop_time, hours

=link_to 'Back', obj_path

Возможно, вы захотите создать собственный конструктор форм, чтобы упростить создание форм.

0 голосов
/ 07 февраля 2010

Мне кажется, что вы можете объединить оба ресурса в один. Давайте просто назовем ресурс «часами», для этого обсуждения. Проблема, связанная с тем, что «час» может принадлежать как бизнесу, так и персоналу, потенциально может быть решена путем превращения отношения в полиморф.

Вы наверняка можете решить эту проблему отношения с has_many_polymorphs:

class Hours < ActiveRecord::Base
  has_many_polymorphs :participants, :from => [:staff, :business], :through => :hours_participants
end

Это потребует новой таблицы и может оказаться не лучшим решением. Тем не менее, это должно быть сухое решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...