state_machine работает только для новых записей - PullRequest
7 голосов
/ 02 ноября 2009

Я не могу заставить камень state_machine (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"

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"

Ответы [ 7 ]

2 голосов
/ 14 апреля 2012

Я столкнулся с той же проблемой через 3 года, поэтому стоит ответить здесь, чтобы сэкономить время других людей.

В вашей таблице должен быть столбец с именем 'state', чтобы state_machine мог сделать состояние постоянным.

Просто добавьте его в свою миграцию - t.string: state

1 голос
/ 06 ноября 2009

Модель вызывает super при инициализации?

В документации state_machine говорится, что для инициализации состояний требуется

def initialize
  @seatbelt_on = false
  super() # NOTE: This *must* be called, otherwise states won't get initialized
end
1 голос
/ 05 ноября 2009

Это все еще происходит при отключенных частичных обновлениях? Comment.partial_updates = false

Если это так, то мы знаем, что проблема заключается в идентификации грязных объектов. Вы должны быть в состоянии позвонить c.state_will_change!, прежде чем позвонить c.publish

1 голос
/ 05 ноября 2009

Не вносит ничего полезного, но я просто хотел сказать, что я также борюсь с этой ошибкой в ​​нескольких state_machines во всем приложении. И я не могу переключиться на AASM, потому что мне нужно иметь более одного state_machine в одной модели ... Так расстраивает!

В любом случае, вы не одиноки, определенно все еще нужно решение.

1 голос
/ 02 ноября 2009

Можете ли вы повторить переходы состояния с помощью публикации **! ** вместо публикации

0 голосов
/ 12 декабря 2009

Попробуйте удалить: состояние из определения:

FROM: state_machine: state,: initial =>: в ожидании do

TO state_machine: initial =>: в ожидании do

0 голосов
/ 05 ноября 2009

Опять не реальный ответ на ваш вопрос, но здесь я попытался смоделировать ваш сеанс:

>> 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 и вставил в нее ваш код.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...