BvuRVKyUVlViVIc7
BvuRVKyUVlViVIc7

Reputation: 11811

AASM state machine exception handling example?

I'm currently working on a class, which is basically doing following:

I try to implement it as following:

class Fetcher < ActiveRecord::Base
  include AASM

  aasm do
    state :created, initial: true
    state :success, :failed

    event :succeed do
      transitions from: :created, to: :success
    end

    event :fail do
      transitions from: :created, to: :failed
    end
  end

  def read_things!(throw_exception = false)
    begin
      raise RuntimeError.new("RAISED EXCEPTION") if throw_exception
      self.content = open("https://example.com?asd=324").read
      self.succeed!
    rescue => e
      self.fail!
    end
  end
end

a = Fetcher.new
a.read_things!(throw_exception = true)
=> state should be failed

a = Fetcher.new
a.read_things!(throw_exception = false)
=> state should be succeess

It works, but looks somehow not really good to do...

I would prefer something like the error handling which is mentioned in the readme

event :read_things do
  before do
    self.content = open("https://example.com?asd=324").read
    self.succeed!
  end
  error do |e|
    self.fail!
  end
  transitions :from => :created, :to => :success
end

but I dont know if this is really the best practice here?

I also have many events, which all should behave like my mentioned error handling is showing above and I saw that I can somehow use error_on_all_events - but didnt find any documentation about it?

Any thoughts? Thanks!

edit: Changed some small parts to remove confusion.

Upvotes: 2

Views: 5086

Answers (1)

vich
vich

Reputation: 11896

First, is the method name fetch! or read_things? In any case, you don't want to pass a boolean argument to determine whether or not to raise an exception. If an exception is raised then your rescue will pick it up:

def read_things
  self.content = open("https://example.com?asd=324").read
  succeed!
rescue => e
  # do something with the error (e.g. log it), otherwise remove the "=> e"
  fail!
end

I would prefer something like the error handling which is mentioned in the readme

Your error handling example is actually good practice (with a few minor edits):

event :read_things do
  before do
    self.content = open("https://example.com?asd=324").read
  end
  error do |e|
    fail! # the self is optional (since self is your Fetcher object)
  end
  transitions from: :created, to: :success
end

In practice:

a = Fetcher.new
a.read_things!

If self.content doesn't raise an exception then the state will transition from created to success (no need to call succeed! directly), otherwise the error handler will call the fail! transition, which will attempt to transition the state to failed.

EDIT:

Example usage of error_on_all_events callback with AASM:

aasm do
  error_on_all_events :handle_error_for_all_events

  state :created, initial: true
  state :success, :failed

  event :succeed do
    transitions from: :created, to: :success
  end

  event :fail do
    transitions from: :created, to: :failed
  end
end

def handle_error_for_all_events
  # inspect the aasm object and handle error...
  puts aasm
end

Upvotes: 2

Related Questions