state_machine 仅适用于新记录
我似乎无法获得 state_machine
gem (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"
即,当我发布
未保存的评论,但是当我尝试发布已保存的评论时,没有任何反应。
另一个编辑:也许是问题的根源?
=> 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"
I can't seem to get the state_machine
gem (http://github.com/pluginaweek/state_machine/) to work on existing records (it works correctly on new records).
Here's my model:
class Comment < ActiveRecord::Base
state_machine :state, :initial => :pending do
event :publish do
transition all => :published
end
end
end
and here's an IRB session that demonstrates the issue (I did ActiveRecord::Base.logger = Logger.new(STDOUT)
to make it easier to read):
>> 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"
I.e., everything works fine when I publish
an unsaved comment, but when I try to publish a comment that's already saved, nothing happens.
Another Edit: Perhaps the root of the problem?
=> 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
I.e., even though the state has actually changed, state_changed?
is returning false and therefore Rails won't update the corresponding database row when I call save
.
It works when I turn off partial updates, but not when I try 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:
More weirdness:
>> 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"
Compare to:
>> 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"
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
三年后我遇到了同样的问题,所以值得在这里回答以节省其他人的时间。
您需要在表中包含名为“state”的列,以便 state_machine 能够使状态持久化。
只需将其添加到您的迁移中 - t.string :state
I came over the same issue 3 years after so it worth answering here to save other folks's time.
You need to have column called 'state' in your table, so state_machine will able to make the state persistant.
Just add it to your migration - t.string :state
您可以使用publish**!**而不是publish重试状态转换吗
Can you please retry your state transitions with publish**!** instead of publish
没有贡献任何有用的东西,但我只是想说,在整个应用程序的多个 state_machines 中,我也在努力解决这个错误。而且我无法切换到 AASM,因为我需要在同一模型中拥有多个 state_machine...太令人沮丧了!
不管怎样,你并不孤单,它肯定还需要一个解决方案。
Not contributing anything useful, but I just wanted to say I'm struggling with this error as well, in multiple state_machines throughout my application. And I can't switch to AASM, because I need to have more than one state_machine in the same model... So frustrating!
Anyway, you're not alone, it definitely still needs a solution.
关闭部分更新后还会发生这种情况吗?
Comment.partial_updates = false
如果是这样,那么我们就知道问题出在识别脏对象上。您应该能够在调用
c.publish
之前调用c.state_will_change!
Does this still happen with partial updates turned off?
Comment.partial_updates = false
If so, then we know the issue is with identifying dirty objects. You should be able to call
c.state_will_change!
before you callc.publish
模型初始化时是否调用 super ?
state_machine 文档说状态需要初始化
Does the model call super when it's initialized?
The state_machine documentation says it's required for states to get initialized
再说一遍,这不是对您问题的真正答案,但在这里我尝试模拟您的会话:
如您所见,它对我来说按预期工作。检查了两次。
(我创建了一个具有主体和状态属性的模型,并将您的代码放入其中。)
Again, not a real answer to your question, but here I tried to simulate your session:
As you can see, it works as expected for me. Checked it twice.
(I created a model with body and state attributes and put your code in it.)
尝试从定义中删除 :state:
FROM:
state_machine:状态,:初始=> :待
处理
状态机:初始=> :待办
Try to remove :state from definition:
FROM:
state_machine :state , :initial => :pending do
TO
state_machine :initial => :pending do