2009-11-02 7 views
7

Ich kann nicht scheinen, die state_machine gem (http://github.com/pluginaweek/state_machine/) zu arbeiten, um vorhandene Datensätze (es funktioniert ordnungsgemäß auf neue Datensätze).state_machine funktioniert nur für neue Datensätze

Hier mein Modell ist:

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

und hier ist eine IRB-Sitzung, der das Problem demonstriert (I ActiveRecord::Base.logger = Logger.new(STDOUT) tat, um es leichter zu lesen):

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

Dh, gut funktioniert alles, wenn ich publish ein nicht gespeicherter Kommentar, aber wenn ich versuche, einen bereits gespeicherten Kommentar zu veröffentlichen, passiert nichts.

Ein anderes Edit: Vielleicht die Wurzel des Problems?

=> 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 

Das heißt, auch wenn der Staat tatsächlich geändert hat, wird state_changed? falsche Rückkehr und damit Rails wird die entsprechende Datenbankzeile nicht aktualisiert, wenn ich save nennen.

Es funktioniert, wenn ich Teil-Updates zu deaktivieren, aber nicht, wenn ich versuche 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:

Weitere Merkwürdigkeit:

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

vergleichen:

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

Im Ernst, das ist ich verrückt (auch mein spezieller Programmier Hut (http://img4.imageshack.us/img4/9105/photo2gw.jpg) war nutzlos) –

+0

: D +1 für den Hut !. Wie auch immer, irgendein Grund, warum Sie den jetzt eingebauten Rails-Zustandsautomaten nicht benutzen? http://blog.envylabs.com/2009/08/the-rails-state-machine/ –

+0

Ist es schon raus? ('include ActiveRecord :: StateMachine' schlägt auf Schienen 2.3.4 für mich fehl) –

Antwort

1

Können Sie bitte mit Ihren Zustandsübergänge wiederholen veröffentlichen ** ** statt

von veröffentlichen
+0

'publish' und' publish! 'Haben den gleichen Effekt in den obigen Beispielen (argh!) –

0

Wieder keine wirkliche Antwort auf Ihre Frage, aber hier habe ich versucht, die Sitzung zu simulieren:

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

Wie Sie sehen können, funktioniert es wie erwartet für mich. Habe es zweimal überprüft. (Ich erstellte ein Modell mit Körper und Zustand Attribute und setzen Sie Ihren Code drin.)

1

Nicht etwas nützliches beitragen, aber ich wollte nur sagen, ich bin mit diesem Fehler auch in mehreren state_machines während meiner Anwendung kämpfen . Und ich kann nicht zu AASM wechseln, weil ich mehr als eine state_machine im selben Modell haben muss ... So frustrierend!

Wie auch immer, Sie sind nicht allein, es braucht definitiv immer noch eine Lösung.

1

Tritt dies immer noch bei deaktivierten Teilupdates auf? Comment.partial_updates = false

Wenn ja, dann wissen wir, dass das Problem bei der Identifizierung von schmutzigen Objekten liegt. Sie sollten c.state_will_change! anrufen können, bevor Sie anrufen c.publish

+0

Dies ist, was ich dachte, ist der wahrscheinliche Täter da dein Update diese Spalte nicht sendet –

+0

Jetzt reden wir darüber! Es funktioniert, wenn ich 'Comment.partial_updates = false 'mache, aber nicht wenn ich' c.state_will_change! '(siehe http://pastie.org/687584 für das, was ich getan habe.) Leider hat dieses Modell einige große Textfelder und daher würde ich es vorziehen, Teilupdates nicht als Workaround zu deaktivieren (obwohl ich state_will_change! Als Workaround implementieren würde, wenn das funktionierte) –

+0

Nach 'c .state_will_change! 'run' c.changed' hat das zurückgegebene Array '' state'' drin? –

1

Ruft das Modell Super, wenn es initialisiert wird?

Die state_machine Dokumentation sagt ist es für Staaten erforderlich

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

Versuchen zu entfernen: Zustand von Definition:

AB: state_machine: Zustand: initial =>: pending tun

TO state_machine: initial =>: ausstehende tun

2

Ich kam über die gleiche Issu 3 Jahre danach lohnt es sich, hier zu antworten, um die Zeit der anderen zu retten.

Sie müssen eine Spalte namens 'state' in Ihrer Tabelle haben, damit state_machine den Zustand dauerhaft machen kann.

Fügen Sie einfach es zu Migration - t.string: Zustand