geekq / workflow

Ruby finite-state-machine-inspired API for modeling workflow
MIT License
1.75k stars 207 forks source link

Concerns + Models + Workflow = error #152

Closed diegorv closed 2 years ago

diegorv commented 9 years ago

Maybe it's my mistake... or not.

versions: rails 4.2 ruby 2.2 workflow 1.2.0

class Contract::Image < ActiveRecord::Base
  include Workflow
  include ImageWorkflow
end
module ImageWorkflow
  extend ActiveSupport::Concern

  included do
    workflow_column :status_layout
  end

  workflow do
    state :awaiting_distribution do
      event :authorize_distribution, transition_to: :not_distributed
      event :cancel                , transition_to: :canceled
    end

    state :not_distributed do
      event :distributed, transition_to: :distributed
      event :cancel     , transition_to: :canceled
    end
  end
end
 x = Contract::Image.first
 => #<Contract::Image id: 1, item_id: 1, status_layout: "not_distributed", created_at: "2015-02-24 11:13:49", updated_at: "2015-02-24 11:14:00">
> x.distributed!
NoMethodError: undefined method `distributed!' for #<Contract::Image:0x007fa7f3ac1e10>
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activemodel-4.2.0/lib/active_model/attribute_methods.rb:433:in `method_missing'
    from (irb):7
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands/console.rb:9:in `start'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:68:in `console'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands.rb:17:in `<top (required)>'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274:in `require'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274:in `block in require'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274:in `require'
    from /Users/diegorv/Dropbox/Sync/Rails/work/erp/bin/rails:8:in `<top (required)>'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/commands/rails.rb:6:in `call'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/command_wrapper.rb:38:in `call'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:183:in `block in serve'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:156:in `fork'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:156:in `serve'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:131:in `block in run'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:125:in `loop'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:125:in `run'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application/boot.rb:18:in `<top (required)>'
    from /Users/diegorv/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
    from /Users/diegorv/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'

> x.current_state
NoMethodError: undefined method `workflow_spec' for ActiveRecord::Base:Class
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activerecord-4.2.0/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/workflow-1.2.0/lib/workflow.rb:153:in `spec'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/workflow-1.2.0/lib/workflow.rb:80:in `current_state'
    from (irb):8
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands/console.rb:9:in `start'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:68:in `console'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/railties-4.2.0/lib/rails/commands.rb:17:in `<top (required)>'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274:in `require'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274:in `block in require'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274:in `require'
    from /Users/diegorv/Dropbox/Sync/Rails/work/erp/bin/rails:8:in `<top (required)>'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/commands/rails.rb:6:in `call'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/command_wrapper.rb:38:in `call'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:183:in `block in serve'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:156:in `fork'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:156:in `serve'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:131:in `block in run'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:125:in `loop'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application.rb:125:in `run'
    from /Users/diegorv/.rvm/gems/ruby-2.2.0/gems/spring-1.3.2/lib/spring/application/boot.rb:18:in `<top (required)>'
    from /Users/diegorv/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
    from /Users/diegorv/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
tijmenb commented 9 years ago

Will this work?

included do
  workflow_column :status_layout

  workflow do
    state :awaiting_distribution do
      (...)
diegorv commented 9 years ago

I tried.

Nop, the same problem.

guyboertje commented 9 years ago

Don't use ActiveSupport::Concern

Plain Ruby will work.

module ImageWorkflow

  workflow_column :status_layout

  workflow do
    state :awaiting_distribution do
      event :authorize_distribution, transition_to: :not_distributed
      event :cancel                , transition_to: :canceled
    end

    state :not_distributed do
      event :distributed, transition_to: :distributed
      event :cancel     , transition_to: :canceled
    end
  end
end
class Contract::Image < ActiveRecord::Base
  include Workflow
  extend ImageWorkflow
end
mountriv99 commented 9 years ago

I had to do the following to make it work:

module ImageWorkflow
  def self.included(base)
    base.workflow_column :status_layout

    base.workflow do
      state :awaiting_distribution do
        event :authorize_distribution, transition_to: :not_distributed
        event :cancel                , transition_to: :canceled
      end

      state :not_distributed do
        event :distributed, transition_to: :distributed
        event :cancel     , transition_to: :canceled
      end
    end
  end
end

class Contract::Image < ActiveRecord::Base
  include Workflow
  include ImageWorkflow
end
guyboertje commented 9 years ago

Maybe as ImageWorkflow is completely dependent on Workflow, you can move the Workflow inclusion statement to the ImageWorkflow module.

Also, you may find some mileage in using a separate ImageWorkflow class that you inject the model into. This technique keeps the model clean and opens up the possibility of having different workflows on a model instance for different sections of the Domain Object (model instance) lifecycle. Think of an Order, you may have Sales, Warehouse, Shipping and Warranty Returns workflows. It would be tricky to include all these states and transitions into one FSM.

It would seem that your workflow above could apply to other kinds of digital files.

davidtolsma commented 8 years ago

In case this helps, this is what i got working using concerns

module ImageWorkflow
  extend ActiveSupport::Concern

  included do
    include ::Workflow

   workflow do
     state :awaiting_distribution do
       event :cancel
     end
   end
end
class Contract::Image < ActiveRecord::Base
  include ImageWorkflow
end