Ответ 1
Если вы ссылаетесь на глянцею state_machine - https://github.com/pluginaweek/state_machine, то он поддерживает аргументы для событий
after_crash do |car, transition|
Log.crash(:car => car, :driver => transition.args.first)
end
Можно ли отправлять переменные в переход? то есть.
@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?
Если вы ссылаетесь на глянцею state_machine - https://github.com/pluginaweek/state_machine, то он поддерживает аргументы для событий
after_crash do |car, transition|
Log.crash(:car => car, :driver => transition.args.first)
end
У меня возникли проблемы со всеми другими ответами, и я обнаружил, что вы можете просто переопределить событие в классе.
class Car
state_machine do
...
event :crash do
transition any => :crashed
end
end
def crash(current_driver)
logger.debug(current_driver)
super
end
end
Просто убедитесь, что вы вызываете "супер" в свой собственный метод
Я не думаю, что вы можете передавать параметры событиям с этим камнем, поэтому, возможно, вы можете попробовать сохранить current_user на @car (временно), чтобы ваш обратный вызов был доступен для него.
В контроллере
@car.driver = current_user
В обратном вызове
after_crash do |car, transition|
create_audit_log car.driver, transition
end
Или что-то в этом роде..:)
Я использовал транзакции вместо обновления объекта и изменения состояния в одном вызове. Например, в действии обновления
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
Другой общий шаблон (см. 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?