Подтвердить что ты не робот

Передача переменных в Rails StateMachine gem transitions

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

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

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

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

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

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

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

Я понимаю.

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

@foo.some_method(current_user)

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

4b9b3361

Ответ 1

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

after_crash do |car, transition|
  Log.crash(:car => car, :driver => transition.args.first)
end

Ответ 2

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

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

Просто убедитесь, что вы вызываете "супер" в свой собственный метод

Ответ 3

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

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

@car.driver = current_user

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

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

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

Ответ 4

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

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

Ответ 5

Другой общий шаблон (см. 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?