pluginaweek / state_machine

Adds support for creating state machines for attributes on any Ruby class
http://www.pluginaweek.org
MIT License
3.74k stars 505 forks source link

Initial state doesn't work in Rails 4.2 #334

Open kalashnikovisme opened 9 years ago

kalashnikovisme commented 9 years ago

Hi, I have problem with initial state in new Rails 4.2

class User < ActiveRecord::Base
  state_machine initial: :waiting_confirmation do
    state :waiting_confirmation
    state :active
  end
end
Loading development environment (Rails 4.2.0)
[1] pry(main)> User.new.state
=> nil

Any ideas?

kalashnikovisme commented 9 years ago

I've solved problem by adding default value for state column, but it's not good.

rails g migration add_default_value_to_user_state
class AddDefaultToUserState < ActiveRecord::Migration
  def change
    change_column_default :users, :state, :waiting_confirmation
  end
end
SaKKo commented 9 years ago

I got the same problem too, i'm using this (for now) (in your model where :draft is initial)

    after_initialize :set_initial_status
    def set_initial_status
      self.status ||= :draft
    end
aripollak commented 9 years ago

This monkey patch seems to work as an initializer, based on #335. But given that this gem seems unmaintained, I'm going to be looking for another alternative.

# Hacks around https://github.com/pluginaweek/state_machine/issues/334
module StateMachine
  module Integrations
    module ActiveRecord
      def define_state_initializer
        define_helper :instance, <<-end_eval, __FILE__, __LINE__ + 1
          def initialize(*)
            super do |*args|
              self.class.state_machines.initialize_states self
              yield(*args) if block_given?
            end
          end
        end_eval
      end
    end
  end
end
SaimonL commented 9 years ago

State machine works fine in Rails 4.1.8. When I run my seed file "rake db:drop:all db:create db:migrate db:seed --trace" in rails 4.2 is get this error:

ActiveRecord::RecordInvalid: Validation failed: State is invalid
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/validations.rb:79:in `raise_record_invalid'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/validations.rb:43:in `save!'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods/dirty.rb:29:in `save!'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/transactions.rb:291:in `block in save!'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/transactions.rb:347:in `block in with_transaction_returning_status'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/transactions.rb:220:in `transaction'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/transactions.rb:344:in `with_transaction_returning_status'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/transactions.rb:291:in `save!'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/integrations/active_record.rb:491:in `block in save!'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/integrations/active_record.rb:506:in `block (2 levels) in around_save'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:150:in `block in run_actions'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:170:in `catch_exceptions'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:148:in `run_actions'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:133:in `run_callbacks'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:212:in `run_callbacks'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:63:in `block (2 levels) in perform'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:63:in `catch'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:63:in `block in perform'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:186:in `within_transaction'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/transition_collection.rb:62:in `perform'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/integrations/active_record.rb:506:in `block in around_save'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/integrations/active_record.rb:534:in `block in transaction'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/transaction.rb:188:in `within_new_transaction'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/transactions.rb:220:in `transaction'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/integrations/active_record.rb:533:in `transaction'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/integrations/active_record.rb:505:in `around_save'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/bundler/gems/state_machine-1a373b2d23a2/lib/state_machine/integrations/active_record.rb:491:in `save!'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/fabrication-2.11.3/lib/fabrication/generator/base.rb:94:in `persist'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/fabrication-2.11.3/lib/fabrication/generator/base.rb:26:in `create'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/fabrication-2.11.3/lib/fabrication/schematic/definition.rb:75:in `block in fabricate'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/fabrication-2.11.3/lib/fabrication/schematic/definition.rb:74:in `instance_eval'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/fabrication-2.11.3/lib/fabrication/schematic/definition.rb:74:in `fabricate'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/fabrication-2.11.3/lib/fabricate.rb:29:in `create'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/fabrication-2.11.3/lib/fabrication.rb:62:in `Fabricate'
/repos/derail/db/seeds.rb:12:in `'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:240:in `load_dependency'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.2.0/lib/rails/engine.rb:547:in `load_seed'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/tasks/database_tasks.rb:250:in `load_seed'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/railties/databases.rake:180:in `block (2 levels) in '
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:240:in `call'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:240:in `block in execute'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:235:in `each'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:235:in `execute'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:179:in `block in invoke_with_call_chain'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/2.1.0/monitor.rb:211:in `mon_synchronize'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:172:in `invoke_with_call_chain'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:165:in `invoke'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:150:in `invoke_task'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:106:in `block (2 levels) in top_level'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:106:in `each'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:106:in `block in top_level'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:115:in `run_with_threads'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:100:in `top_level'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:78:in `block in run'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:176:in `standard_exception_handling'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:75:in `run'
/home/saimon/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/bin/rake:33:in `'
/home/saimon/.rbenv/versions/2.1.5/bin/rake:23:in `load'
/home/saimon/.rbenv/versions/2.1.5/bin/rake:23:in `
' Tasks: TOP => db:seed

I installed state machine via Gemfile:

gem 'state_machine', git: 'https://github.com/seuros/state_machine.git'

The code where this happens:

  repo = Fabricate(:repo, project: project, server_url: 'CustomLogger',  server_type: 'GitHub')

Fabricate is same as FactoryGirl.create(:repo, ...) The validation only looks for presence of project, server_url, and server_type.

Repo is an AcriveRecord Model which has this state code:

 state_machine :state, initial: :ready do
    state :retrieved
    state :pulled
    state :removed
    event :retrieve do
      transition ready: :retrieved
      transition removed: :retrieved
    end
    event :pull do
      transition retrieved: :pulled
      transition pulled: :pulled
      transition compleated: :pulled
    end
    event :remove do
      transition retrieved: :removed
      transition pulled: :removed
      transition compleated: :removed
    end
  end
nfedyashev commented 9 years ago

@SaKKo @kalashnikovisme thanks for posting workarounds!

xinuc commented 9 years ago

confirmed this issue.

d0minicw0ng commented 9 years ago

+1

Mehonoshin commented 9 years ago

If the gem is not maintained anymore, maybe someone wants to maintain its fork?

nfedyashev commented 9 years ago

@Mehonoshin https://github.com/pluginaweek/state_machine/issues/310

advantgroup commented 9 years ago

@SaimonL +1 Exactly the same problem. Find a fix?

lucascaton commented 9 years ago

@pluginaweek any news on this? Thanks.

rusterholz commented 9 years ago

Guys, @seuros maintains a fork of this which does not exhibit this issue when used with Rails 4.2. See discussion here: https://github.com/pluginaweek/state_machine/issues/310

SaimonL commented 9 years ago

The solution is you have to set default state in the database level. so the migration file will look like this:

t.string :status, default: 'start'

Having the state nil will cause error. Don't know about the updated versions.

jakehockey10 commented 9 years ago

This worked for me in development, but not in production on Heroku.

seuros commented 9 years ago

Guys, just use state_machines-activerecord.

kalashnikovisme commented 9 years ago

I use https://github.com/seuros/state_machine with Rails 4.2

everything work now

seuros commented 9 years ago

@kalashnikovisme https://github.com/state-machines/state_machines-activerecord

shlima commented 9 years ago

+1

khaleksa commented 9 years ago

+1

mkonikowski commented 9 years ago

+1

styx commented 9 years ago

@mkonikowski @shlima @khaleksa This repo is not supported. Development moved to: https://github.com/state-machines/state_machines-activerecord

mkonikowski commented 9 years ago

@styx I've discovered it already, but forgot to comment here... Maybe in the Readme you could add info that this repo is not maintained anymore and put a link to state_machines-activerecord as the most recent one?

seuros commented 9 years ago

@mkonikowski Nobody has access to this repo anymore. That why we have the other one :)

scrooloose commented 9 years ago

@seuros - thanks, I am now using state_machines-activerecord

klebervirgilio commented 8 years ago

+1

dosire commented 8 years ago

MR with fix https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/1764