How to define a state_machine in a Concern?

2020-07-17 07:19发布

问题:

I am trying to factor out some duplicated logic into a concern. Part of the duplicated logic is a state_machine.

Simplified, the Database, Site, SftpUser and more contain, amongst others, this:

class Database < ActiveRecord::Base
  # ...
  state_machine :deploy_state, initial: :halted do
    state :pending
  end
end

I'm attempting to refactor this into a concern:

module Deployable
  extend ActiveSupport::Concern

  included do
    state_machine :deploy_state, initial: :halted do
      state :pending
    end
  end
end

# Tested with:
class DeployableDouble < ActiveRecord::Base
  extend Deployable
end

describe DeployableDouble do
  let(:subject) { DeployableDouble.new }

  it "should have default state halted" do
    subject.deploy_state.must_equal "halted"
  end
end

However, this is not the correct way to implement a state_machnine in a concern, because this results in: NoMethodError: undefined method 'deploy_state' for <DeployableDouble:0xb9831f8>. Which indicates that the Double did not get a statemachine assigned at all.

Is the included do actually the right callback to implement this? Is it maybe an issue with state_machine, it needing a subclass of ActiveRecord::Base or so? Something I'm not getting? I am pretty new to the concept of Concerns.

回答1:

Okay. I am feeling really stupid. One should not extend a class with a module, but include that module. Obviously.

# Tested with:
class DeployableDouble
  include Deployable
end

One of these things that you oversee once written. Also, extending the ActiveRecord::Base is not needed, since state_machine is just plain old Ruby and works on a generic Ruby Object.