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_machine 将能够使状态持久化。

只需将其添加到您的迁移中 - t.string :state

于 2012-04-14T01:46:18.200 回答
1

模型初始化时是否调用 super ?

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

您能否使用发布**重试您的状态转换!** 而不是发布

于 2009-11-02T15:38:02.550 回答
1

关闭部分更新后还会发生这种情况吗?Comment.partial_updates = false

如果是这样,那么我们知道问题在于识别脏对象。你应该可以在打电话c.state_will_change!之前打电话c.publish

于 2009-11-05T20:20:44.790 回答
1

没有贡献任何有用的东西,但我只想说我也在为这个错误而苦苦挣扎,在我的应用程序中的多个 state_machines 中。而且我不能切换到 AASM,因为我需要在同一个模型中拥有多个 state_machine……太令人沮丧了!

无论如何,你并不孤单,它肯定仍然需要一个解决方案。

于 2009-11-05T19:53:14.210 回答
0

尝试从定义中删除 :state :

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

TO state_machine :initial => :pending do

于 2009-12-12T16:28:28.050 回答
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"

如您所见,它对我来说按预期工作。检查了两次。(我创建了一个具有 body 和 state 属性的模型并将您的代码放入其中。)

于 2009-11-05T07:19:36.823 回答