7

state_machinegem ( http://github.com/pluginaweek/state_machine/ ) を既存のレコードで動作させることができないようです(新しいレコードで正しく動作します)。

これが私のモデルです:

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

そして、これが問題を示すIRBセッションです(ActiveRecord::Base.logger = Logger.new(STDOUT)読みやすくするために行いました):

>> 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 を返しているため、Rails は を呼び出したときに対応するデータベース行を更新しません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"

編集:

さらに奇妙:

>> 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"
4

7 に答える 7

2

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

テーブルに「state」という列が必要です。これにより、state_machineは状態を永続化できます。

移行に追加するだけです-t.string:state

于 2012-04-14T01:46:18.200 に答える
1

モデルは初期化時にスーパーを呼び出しますか?

state_machine のドキュメントには、状態を初期化する必要があると書かれています

def initialize
  @seatbelt_on = false
  super() # NOTE: This *must* be called, otherwise states won't get initialized
end
于 2009-11-06T04:30:34.197 に答える
1

publish の代わりに publish**!** を使用して状態遷移を再試行できますか

于 2009-11-02T15:38:02.550 に答える
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 属性を持つモデルを作成し、その中にコードを入れました。)

于 2009-11-05T07:19:36.823 に答える
0

定義から :state を削除してみてください:

FROM: state_machine :state , :initial => :pending do

TO state_machine :initial => :pending do

于 2009-12-12T16:28:28.050 に答える