Шаблон дизайна модели состояния - PullRequest
3 голосов
/ 25 августа 2009

У меня проблемы с реализацией статусов для модели. Вероятно, это связано с неправильным дизайном.

Существует модель, которая имеет статус. Может быть несколько экземпляров модели и только несколько предопределенных состояний (например: созданный, обновленный, восстановленный и т. Д.). Для каждого отдельного статуса есть некоторая логика расчета для модели. Например. model.cost() рассчитывается по-разному для каждого статуса.

Я бы хотел, чтобы ActiveRecord автоматически устанавливал правильные значения model_status_id при сохранении модели. Я думаю, что в идеальной ситуации я мог бы сделать что-то вроде этого:

model.status = StatusModel.retrieved

и

case status
  when renewed
    # ...
  when retrieved
    # ..
end

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

ModelStatus < ActiveRecord::Base
  has_many :models
Model < ActiveRecord::Base
  belongs_to :model_status

Однако это вызывает у меня много проблем в коде. У кого-нибудь есть хорошие идеи или шаблоны для этого?

Ответы [ 3 ]

2 голосов
/ 25 августа 2009

То, что вы описываете, кажется идеальным случаем для конечного автомата.

Существует много реализаций конечного автомата Ruby. Вы можете увидеть довольно представительный список на ruby-toolbox

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

Ваш пример будет выглядеть как

model.retrieve!

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

1 голос
/ 25 августа 2009

Также попробуйте взглянуть на плагин acts_as_state_machine. Я недавно использовал его в проекте, и он работал хорошо.

1 голос
/ 25 августа 2009

Почему бы не сохранить статусную часть реальной модели? Если они предопределены, это не слишком много работы:

class Model < ActiveRecord::Base

  STAT_CREATED   = 1 
  STAT_RENEWED   = 2
  STAT_RETRIEVED = 4

  validates_inclusion_of :status,
                         :in => [1, 2, 4]


  def created?
    status & STAT_CREATED
  end

  def renewed?
    status & STAT_RENEWED
  end

  def retrieved?
    status & STAT_RETRIEVED
  end

end

Таким образом, вы можете либо протестировать экземпляр модели напрямую (например, если @ model.created?), Либо написать свои выражения case следующим образом:

case @model.status
when Model::STAT_CREATED
...
when Model::STAT_RENEWED
...
...