Передача переменных в Rails StateMachine gem переходов - PullRequest
16 голосов
/ 19 августа 2010

Можно ли отправлять переменные при переходе? т.е.

@car.crash!(:crashed_by => current_user)

В моей модели есть обратные вызовы, но мне нужно отправить их пользователю, который спровоцировал переход

after_crash do |car, transition|
  # Log the car crashers name
end

Я не могу получить доступ к current_user, потому что я в модели, а не в Controller / View.

И прежде чем ты это скажешь ... Я знаю, я знаю.

Не пытаться получить доступ к переменным сеанса в модели

Я понял.

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

@foo.some_method(current_user)

и моя модель Foo будет ожидать, что какой-то пользователь спровоцирует some_method, но как мне сделать это с переходом с гема StateMachine?

Ответы [ 5 ]

33 голосов
/ 14 июня 2011

Если вы ссылаетесь на гем state_machine - https://github.com/pluginaweek/state_machine - тогда он поддерживает аргументы событий

after_crash do |car, transition|
  Log.crash(:car => car, :driver => transition.args.first)
end
7 голосов
/ 09 октября 2012

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

class Car
  state_machine do
    ...
    event :crash do
      transition any => :crashed
    end
  end
  def crash(current_driver)
    logger.debug(current_driver)
    super
  end
end

Просто обязательно вызовите "super" в вашем пользовательском методе

2 голосов
/ 19 августа 2010

Я не думаю, что вы можете передавать параметры событиям с этим гемом, поэтому, возможно, вы можете попытаться сохранить current_user на @car (временно), чтобы ваш обратный вызов аудита мог получить к нему доступ.

В контроллере

@car.driver = current_user

В обратном вызове

after_crash do |car, transition|
   create_audit_log car.driver, transition
end

Или что-то в этом роде ..:)

1 голос
/ 13 января 2014

Я использовал транзакции вместо обновления объекта и изменения состояния за один вызов.Например, в действии обновления,

ActiveRecord::Base.transaction do
  if @car.update_attribute!(:crashed_by => current_user)
    if @car.crash!()
      format.html { redirect_to @car }
    else
      raise ActiveRecord::Rollback
  else
    raise ActiveRecord::Rollback
  end
end
0 голосов
/ 15 августа 2013

Другой распространенный шаблон (см. state_machine docs ), который избавляет вас от необходимости передавать переменные между контроллером и моделью, - это динамическое определение метода проверки состояния в методе обратного вызова. Это не очень элегантно в приведенном выше примере, но может быть предпочтительным в тех случаях, когда модель должна обрабатывать одну и ту же переменную (и) в разных состояниях. Например, если в вашей модели автомобиля у вас были состояния «сбой», «украдено» и «заимствовано», все из которых могут быть связаны с ответственным лицом, вы можете получить:

state :crashed, :stolen, :borrowed do
  def blameable?
    true
  end

state all - [:crashed, :stolen, :borrowed] do
  def blameable?
    false
  end

Затем в контроллере вы можете сделать что-то вроде:

car.blame_person(person) if car.blameable?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...