2009-11-02 1 views
7

state_machine gem(http://github.com/pluginaweek/state_machine/)を既存のレコードで動作させることはできません(新しいレコードでは正しく動作します)。ここでstate_machineは新しいレコードでのみ動作します

は私のモデルです:

class Comment < ActiveRecord::Base 
    state_machine :state, :initial => :pending do 
    event :publish do 
     transition all => :published 
    end 
    end 
end 

、ここでは、問題(私は読みやすくするためにActiveRecord::Base.logger = Logger.new(STDOUT)をした)証明するIRBのセッションです:

>> c = Comment.new 
=> #<Comment id: nil, song_id: nil, author: nil, body: nil, created_at: nil, updated_at: nil, state: "pending"> 
>> c.state 
=> "pending" 
>> c.publish 
    Comment Create (0.6ms) INSERT INTO "comments" ("updated_at", "body", "author", "song_id", "created_at", "state") VALUES('2009-11-02 02:44:37', NULL, NULL, NULL, '2009-11-02 02:44:37', 'published') 
=> true 
>> Comment.last.state 
    Comment Load (0.4ms) SELECT * FROM "comments" ORDER BY comments.id DESC LIMIT 1 
=> "published" 
>> c = Comment.create 
    Comment Create (0.5ms) INSERT INTO "comments" ("updated_at", "body", "author", "song_id", "created_at", "state") VALUES('2009-11-02 02:44:47', NULL, NULL, NULL, '2009-11-02 02:44:47', 'pending') 
=> #<Comment id: 4, song_id: nil, author: nil, body: nil, created_at: "2009-11-02 02:44:47", updated_at: "2009-11-02 02:44:47", state: "pending"> 
>> c.publish 
=> true 
>> c.save 
=> true 
>> Comment.last.state 
    Comment Load (0.4ms) SELECT * FROM "comments" ORDER BY comments.id DESC LIMIT 1 
=> "pending" 

すなわちとき、私、すべてが正常に動作しますpublish未保存のコメントですが、すでに保存されているコメントを公開しようとすると何も起こりません。

別の編集:おそらく問題の根本?

=> true 
>> a = Comment.last 
    Comment Load (1.3ms) SELECT * FROM "comments" ORDER BY comments.id DESC LIMIT 1 
=> #<Comment id: 3, song_id: nil, author: nil, body: nil, created_at: "2009-11-03 03:03:54", updated_at: "2009-11-03 03:03:54", state: "pending"> 
>> a.state 
=> "pending" 
>> a.publish 
=> true 
>> a.state 
=> "published" 
>> a.state_changed? 
=> false 

、すなわち、状態が実際に変化しているにもかかわらず、state_changed?がfalseを返すと私はsaveを呼び出すとき従ってレールは、対応するデータベースの行を更新しないであろう。

私は部分的な更新をオフにするとそれは動作しますが、私はstate_will_change!を試していないとき:

>> Comment.partial_updates = false 
=> false 
>> c = Comment.create 
    Comment Create (0.5ms) INSERT INTO "comments" ("updated_at", "body", "author", "song_id", "created_at", "state") VALUES('2009-11-07 05:06:49', NULL, NULL, NULL, '2009-11-07 05:06:49', 'pending') 
=> #<Comment id: 7, song_id: nil, author: nil, body: nil, created_at: "2009-11-07 05:06:49", updated_at: "2009-11-07 05:06:49", state: "pending"> 
>> c.publish 
    Comment Update (0.9ms) UPDATE "comments" SET "created_at" = '2009-11-07 05:06:49', "author" = NULL, "state" = 'published', "body" = NULL, "song_id" = NULL, "updated_at" = '2009-11-07 05:06:53' WHERE "id" = 7 
=> true 
>> Comment.last.state 
    Comment Load (0.5ms) SELECT * FROM "comments" ORDER BY comments.id DESC LIMIT 1 
=> "published" 
>> Comment.partial_updates = true 
=> true 
>> c = Comment.create 
    Comment Create (0.8ms) INSERT INTO "comments" ("updated_at", "body", "author", "song_id", "created_at", "state") VALUES('2009-11-07 05:07:21', NULL, NULL, NULL, '2009-11-07 05:07:21', 'pending') 
=> #<Comment id: 8, song_id: nil, author: nil, body: nil, created_at: "2009-11-07 05:07:21", updated_at: "2009-11-07 05:07:21", state: "pending"> 
>> c.state_will_change! 
=> "pending" 
>> c.publish 
=> true 
>> c.save 
=> true 
>> Comment.last.state 
    Comment Load (0.5ms) SELECT * FROM "comments" ORDER BY comments.id DESC LIMIT 1 
=> "pending" 

EDIT:

もっとおかしな:

>> a = Comment.last 
    Comment Load (1.2ms) SELECT * FROM "comments" ORDER BY comments.id DESC LIMIT 1 
=> #<Comment id: 5, song_id: nil, author: nil, body: nil, created_at: "2009-11-02 06:33:19", updated_at: "2009-11-02 06:33:19", state: "pending"> 
>> a.state 
=> "pending" 
>> a.publish 
=> true 
>> a.state 
=> "published" 
>> a.save 
=> true 
>> a.id 
=> 5 
>> Comment.find(5).state 
    Comment Load (0.3ms) SELECT * FROM "comments" WHERE ("comments"."id" = 5) 
=> "pending" 

と比較:

>> a = Comment.last 
    Comment Load (0.3ms) SELECT * FROM "comments" ORDER BY comments.id DESC LIMIT 1 
=> #<Comment id: 5, song_id: nil, author: nil, body: nil, created_at: "2009-11-02 06:33:19", updated_at: "2009-11-02 06:33:19", state: "pending"> 
>> a.state = "published" 
=> "published" 
>> a.save 
    Comment Update (0.6ms) UPDATE "comments" SET "state" = 'published', "updated_at" = '2009-11-02 08:29:34' WHERE "id" = 5 
=> true 
>> a.id 
=> 5 
>> Comment.find(5).state 
    Comment Load (0.4ms) SELECT * FROM "comments" WHERE ("comments"."id" = 5) 
=> "published" 
+6

を真剣に、これは私が狂いそうです(でも、私の特別なプログラミングの帽子(http://img4.imageshack.us/img4/9105/photo2gw.jpg )は役に立たなかった) –

+0

:D +1!とにかく、現在組み込まれているRails状態マシンを使用していない理由は何ですか? http://blog.envylabs.com/2009/08/the-rails-state-machine/ –

+0

まだですか? ( 'include ActiveRecord :: StateMachine'が私のためにレール2.3.4で失敗します) –

答えて

1

あなたは** **の代わりに、もう一度あなたの質問に本当の答え

+0

'publish'と' publish! 'は上記の例で同じ効果を持っています –

0

ではなく公開し、公開してあなたの状態遷移を再試行してくださいすることができますが、ここで私はあなたのセッションをシミュレートしてみました:

>> c = Comment.new 
=> #<Comment id: nil, body: nil, created_at: nil, updated_at: nil, state: "pending"> 
>> c.state 
=> "pending" 
>> c.publish 
=> true 
>> Comment.last.state 
=> "published" 
>> c = Comment.create 
=> #<Comment id: 4, body: nil, created_at: "2009-11-05 07:12:53", updated_at: "2009-11-05 07:12:53", state: "pending"> 
>> c.publish 
=> true 
>> c.save 
=> true 
>> Comment.last.state 
=> "published" 

ご覧のとおり、期待どおりに動作します。それを2回チェックした。 (bodyとstateの属性を持つモデルを作成してコードを入れました)

1

役に立つものはありませんが、アプリケーション全体の複数のstate_machinesでこのエラーにも苦しんでいると言いたいと思います。同じモデルで複数のstate_machineを持つ必要があるので、私はAASMに切り替えることはできません...だからイライラします!

とにかく、あなたは一人ではありません。解決策が必要です。

1

これは部分的な更新を無効にしても起こりますか? Comment.partial_updates = false

もしそうなら、問題は汚れたオブジェクトを特定することです。あなたはそれが初期化されますときc.publish

+0

これは私が考えていたものです –

+0

今話しています! 'Comment.partial_updates = false'を実行しても動作しますが、' c.state_will_change! '(http://pastie.org参照)では動作しません。/687584)。残念ながら、このモデルにはいくつかの大きなテキストフィールドがあるので、回避策として部分的な更新を無効にしたくないのですが(それがうまくいけば回避策としてstate_will_changeを実装します) –

+0

'c .state_will_change! '実行' c.changed'返された配列に '' state "'がありますか? –

1

は、モデルのコールスーパー行いませ呼び出す前にc.state_will_change!を呼び出すことができるでしょうか?状態の定義から:

state_machineのドキュメントは、それが

def initialize 
    @seatbelt_on = false 
    super() # NOTE: This *must* be called, otherwise states won't get initialized 
end 
0

を削除するようにしてください初期化され得るために、状態のために必要だと言う

FROM: state_machine:状態、:=>初期:保留

を行います

TO state_machine:initial =>:保留中

2

私は同じissuに来ました3年後、他の人々の時間を節約するためにここで答える価値があります。

テーブルに 'state'という列がある必要があります。したがって、state_machineは状態を持続させることができます。

ちょうどあなたの移行に追加 - t.string:状態

関連する問題