# Acts\_as\_state\_machine: bug?! obj.save doesn't work

**URL:** <https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002>\
**Category:** Rails\
**Created:** [April 20, 2009, 10:24pm UTC](https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002 "2009-04-20T22:24:22Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 20, 2009, 10:24pm UTC](https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002/1 "2009-04-20T22:24:22Z")

</div>

Hi all

I’m trying to understand, what acts\_as\_state\_machine really does (I use  
it because restful\_authentication uses it).

restful\_authentication defines the following stuff:

acts\_as\_state\_machine :initial =\> :pending  
state :passive  
state :pending, :enter =\> :make\_activation\_code  
state :active, :enter =\> :do\_activate  
state :suspended  
state :deleted, :enter =\> :do\_delete

event :register do  
transitions :from =\> :passive, :to =\> :pending, :guard =\> Proc.new  
{|u| !(u.crypted\_password.blank? && u.password.blank?) }  
end

event :activate do  
transitions :from =\> :pending, :to =\> :active  
end

event :suspend do  
transitions :from =\> [:passive, :pending, :active], :to =\>  
:suspended  
end

event :delete do  
transitions :from =\> [:passive, :pending, :active, :suspended], :to  
=\> :deleted  
end

event :unsuspend do  
transitions :from =\> :suspended, :to =\> :active, :guard =\> Proc.new  
{|u| !u.activated\_at.blank? }  
transitions :from =\> :suspended, :to =\> :pending, :guard =\> Proc.new  
{|u| !u.activation\_code.blank? }  
transitions :from =\> :suspended, :to =\> :passive  
end

I played a bit with the console…

josh$ script/console  
Loading development environment (Rails 2.1.0)

> > record = User.new({ :login =\> ‘quire’, :email =\> ‘removed\_email\_address@domain.invalid’, :password =\> ‘quire’, :password\_confirmation =\> ‘quire’ })  
> > =\> #\<User id: nil, first\_name: nil, last\_name: nil, login: “quire”,  
> > email: “removed\_email\_address@domain.invalid”, remember\_token: nil, crypted\_password: nil,  
> > password\_reset\_code: nil, salt: nil, activation\_code: nil,  
> > remember\_token\_expires\_at: nil, activated\_at: nil, deleted\_at: nil,  
> > state: “passive”, created\_at: nil, updated\_at: nil\>

Why is the state “passive”? Is the state of an unsaved object always  
“passive”?

> > record.save  
> > =\> true
> 
> > record  
> > =\> #\<User id: 4, first\_name: nil, last\_name: nil, login: “quire”, email:  
> > “removed\_email\_address@domain.invalid”, remember\_token: nil, crypted\_password:  
> > “5670fb5c84b89d64ef405b315e4337304f88dc2b”, password\_reset\_code: nil,  
> > salt: “a6ff544223bf2a7653651ea7f29888a195155c8d”, activation\_code:  
> > “43745d2e79d7aab4dfe2b4a3bd64d8ac577aeafe”, remember\_token\_expires\_at:  
> > nil, activated\_at: nil, deleted\_at: nil, state: “pending”, created\_at:  
> > “2009-04-20 20:19:15”, updated\_at: “2009-04-20 20:19:15”\>

Looks good so far… But when looking at the database entry, the  
activation\_code actually is NULL! Let’s prove this:

> > record.reload  
> > =\> #\<User id: 4, first\_name: nil, last\_name: nil, login: “quire”, email:  
> > “removed\_email\_address@domain.invalid”, remember\_token: nil, crypted\_password:  
> > “5670fb5c84b89d64ef405b315e4337304f88dc2b”, password\_reset\_code: nil,  
> > salt: “a6ff544223bf2a7653651ea7f29888a195155c8d”, activation\_code: nil,  
> > remember\_token\_expires\_at: nil, activated\_at: nil, deleted\_at: nil,  
> > state: “pending”, created\_at: “2009-04-20 20:19:15”, updated\_at:  
> > “2009-04-20 20:19:15”\>

Tadaah! This is a serious bug, isn’t it? The User object only works  
correct when using “register!” instead of save:

josh$ script/console  
Loading development environment (Rails 2.1.0)

> > record = User.new({ :login =\> ‘quire’, :email =\> ‘removed\_email\_address@domain.invalid’, :password =\> ‘quire’, :password\_confirmation =\> ‘quire’ })  
> > =\> #\<User id: nil, first\_name: nil, last\_name: nil, login: “quire”,  
> > email: “removed\_email\_address@domain.invalid”, remember\_token: nil, crypted\_password: nil,  
> > password\_reset\_code: nil, salt: nil, activation\_code: nil,  
> > remember\_token\_expires\_at: nil, activated\_at: nil, deleted\_at: nil,  
> > state: “passive”, created\_at: nil, updated\_at: nil\>
> 
> > record.register!  
> > =\> true
> 
> > record.reload  
> > =\> #\<User id: 5, first\_name: nil, last\_name: nil, login: “quire”, email:  
> > “removed\_email\_address@domain.invalid”, remember\_token: nil, crypted\_password:  
> > “465f2d6572f47e9adec58022d938b134e570077b”, password\_reset\_code: nil,  
> > salt: “293aaa4b1a391f472803767c93c07bf7966e9141”, activation\_code:  
> > “1129116e89f989fee4dccb7eb38946c8e16af93a”, remember\_token\_expires\_at:  
> > nil, activated\_at: nil, deleted\_at: nil, state: “pending”, created\_at:  
> > “2009-04-20 20:22:03”, updated\_at: “2009-04-20 20:22:03”\>

Can anyone approve this? In my oppinion, save should have exactly the  
same effect like “register!”… but it definitely doesn’t.

Thanks for your opinion.  
Josh

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 21, 2009, 8:30am UTC](https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002/2 "2009-04-21T08:30:31Z")

</div>

Not sure I understand your problem…

event :register do  
transitions :from =\> :passive,  
:to =\> :pending,  
:guard =\> Proc.new {|u|  
!(u.crypted\_password.blank? &&  
u.password.blank?) }  
end

sort of tells me that UsersController#register causes a state  
transition from :passive to :pending

and

event :activate do  
transitions :from =\> :pending, :to =\> :active  
end

UsersController#activate causes a state transition from :pending  
to :active

I don’t see any mention of UsersController#save anywhere in either  
restful\_authentication/lib/… or in the controllers and views created  
using script/generate authenticated User Sessions --options…

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 21, 2009, 11:04am UTC](https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002/3 "2009-04-21T11:04:48Z")

</div>

Rick Lloyd wrote:

> Not sure I understand your problem…
> 
> I don’t see any mention of UsersController#save anywhere in either  
> restful\_authentication/lib/… or in the controllers and views created  
> using script/generate authenticated User Sessions --options…

The save method is the original ActiveRecord save method. It doesn’t  
have to do anything with acts\_as\_state\_machine! 😉

Just look at the following to see what I mean:

josh$ script/console  
Loading development environment (Rails 2.1.0)

> > record = User.new({ :login =\> ‘quire’, :email =\> ‘removed\_email\_address@domain.invalid’, :password =\> ‘quire’, :password\_confirmation =\> ‘quire’ })  
> > =\> #\<User … activation\_code: nil, state: “passive” …\> # No  
> > activation code, state is passive

Why is the state passive? In my opinion it should be pending because of  
this line:

acts\_as\_state\_machine :initial =\> :pending

And because in my opinion it should be pending, it should also have an  
activation code:

state :pending, :enter =\> :make\_activation\_code

However, it doesn’t so far.

> > record.save  
> > =\> true
> 
> > record  
> > =\> #\<User … activation\_code:  
> > “996b495dcbb15a61cdda19ef5da07a78b27dff87”, state: “pending” … \>

Well, after calling ActiveRecord’s save method it seems to have changed  
to the pending state, and the activation\_code is available. Looks quite  
good, so far.

In my opinion, the activation\_code should now also be saved to the DB.  
So let’s check this:

> > record.reload  
> > =\> #\<User … activation\_code: nil, state: “pending” … \>

So here we have the problem! The activation\_code is nil again! No idea  
why, but it’s nil!

The only way to get this stuff to work is by calling the “register!”  
method:

josh$ script/console  
Loading development environment (Rails 2.1.0)

> > record = User.new({ :login =\> ‘quire’, :email =\> ‘removed\_email\_address@domain.invalid’, :password =\> ‘quire’, :password\_confirmation =\> ‘quire’ })  
> > =\> #\<User id: nil, first\_name: nil, last\_name: nil, login: “quire”,  
> > email: “removed\_email\_address@domain.invalid”, remember\_token: nil, crypted\_password: nil,  
> > password\_reset\_code: nil, salt: nil, activation\_code: nil,  
> > remember\_token\_expires\_at: nil, activated\_at: nil, deleted\_at: nil,  
> > state: “passive”, created\_at: nil, updated\_at: nil\>
> 
> > record.register!  
> > =\> true
> 
> > record  
> > =\> #\<User … activation\_code:  
> > “f8395f836ec66c9db966da457ba19cdf5f29dd0a”, state: “pending” … \>
> 
> > record.reload  
> > =\> #\<User … activation\_code:  
> > “d5402915503a0c3f1a9eb984c116bc0ae4c07877”, state: “pending” … \> # The  
> > activation\_code stays now

This doesn’t make any sense to me. The only thing that “register!” does  
is changing the state from “passive” to “pending”:

event :register do  
transitions :from =\> :passive, :to =\> :pending, :guard =\> Proc.new  
{|u| !(u.crypted\_password.blank? && u.password.blank?) }  
end

OK, this sounds reasonable, but then I don’t understand, why and where  
the state is changed when calling save (it’s exactly the same transition  
from “passive” to “pending” as when calling register!), and why the  
activation\_code gets lost in this case…?

Looks everything really strange to me… You see my problem now?

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 21, 2009, 6:25pm UTC](https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002/4 "2009-04-21T18:25:56Z")

</div>

Perhaps the AASM library is buggy. I haven’t used it in ages, but I  
seem to recall some issue of it not calling the enter transition unless  
the event was manually triggered. That’s what the behavior above  
suggests.

If the library is giving you hassles, then generate the authentication  
code without the aasm flag. This code was submitted to me by someone  
else, and I don’t have much experience with it.

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 21, 2009, 6:28pm UTC](https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002/5 "2009-04-21T18:28:53Z")

</div>

Rick O. wrote:

> Perhaps the AASM library is buggy. I haven’t used it in ages, but I  
> seem to recall some issue of it not calling the enter transition unless  
> the event was manually triggered. That’s what the behavior above  
> suggests.
> 
> If the library is giving you hassles, then generate the authentication  
> code without the aasm flag. This code was submitted to me by someone  
> else, and I don’t have much experience with it.

First of all thanks a lot for taking this serious and answering me upon  
my request, Rick. 🙂

What do you suggest? Should I try to find the bug in AASM and submit a  
fix? I don’t like to use workarounds for evidently buggy software… 😉

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 21, 2009, 11:59pm UTC](https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002/6 "2009-04-21T23:59:10Z")

</div>

> You can now follow the sequence:
> 
> > > record = User.new({ :login =\> ‘quire’, :email =\> ‘removed\_email\_address@domain.invalid’, :password =\> ‘enquire’, :password\_confirmation =\> ‘enquire’ })  
> > > =\> #\<User id: nil, login: “quire”, name: “”, email:  
> > > “removed\_email\_address@domain.invalid”, crypted\_password: nil, salt: nil, created\_at:  
> > > nil, updated\_at: nil, remember\_token: nil, remember\_token\_expires\_at:  
> > > nil, activation\_code: nil, activated\_at: nil, state: “passive”,  
> > > deleted\_at: nil\>
> > 
> > > record.save  
> > > =\> true
> > 
> > > record  
> > > =\> #\<User id: nil, login: “quire”, name: “”, email:  
> > > “removed\_email\_address@domain.invalid”, crypted\_password: nil, salt: nil, created\_at:  
> > > nil, updated\_at: nil, remember\_token: nil, remember\_token\_expires\_at:  
> > > nil, activation\_code: “8508423584b5c775a60939f9d1966653cd8ea493”,  
> > > activated\_at: nil, state: “pending”, deleted\_at: nil\>

Actually, you forgot to reload the model, because THAT caused the  
problem…

And it seems that we don’t use the same version of the  
restful\_authentication plugin, because mine doesn’t contain a file  
called aasm\_roles.rb; take a look at the attached screen…

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 21, 2009, 10:09pm UTC](https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002/7 "2009-04-21T22:09:58Z")

</div>

You might want to look at this a little closer before you submit a bug  
report. For instance, if you make two changes:

1. FILE: app/controllers/users\_controller.rb  
IN: def create  
FROM: @user.register! if @user && @user.valid?  
TO: @user.save! if @user && @user.valid?

2. FILE: vendor/plugins/restful-authentication/lib/authorization/  
aasm\_roles.rb  
FROM: aasm\_event :register do  
TO: aasm\_event :save do

You can now follow the sequence:

> > record = User.new({ :login =\> ‘quire’, :email =\> ‘removed\_email\_address@domain.invalid’, :password =\> ‘enquire’, :password\_confirmation =\> ‘enquire’ })  
> > =\> #\<User id: nil, login: “quire”, name: “”, email:  
> > “removed\_email\_address@domain.invalid”, crypted\_password: nil, salt: nil, created\_at:  
> > nil, updated\_at: nil, remember\_token: nil, remember\_token\_expires\_at:  
> > nil, activation\_code: nil, activated\_at: nil, state: “passive”,  
> > deleted\_at: nil\>  
> > record.save  
> > =\> true  
> > record  
> > =\> #\<User id: nil, login: “quire”, name: “”, email:  
> > “removed\_email\_address@domain.invalid”, crypted\_password: nil, salt: nil, created\_at:  
> > nil, updated\_at: nil, remember\_token: nil, remember\_token\_expires\_at:  
> > nil, activation\_code: “8508423584b5c775a60939f9d1966653cd8ea493”,  
> > activated\_at: nil, state: “pending”, deleted\_at: nil\>

Of course, you can not actually save record to the database anymore  
since you’ve masked ActiveRecord’s save method. There’s probably a  
way to clear that up as well but that’s not your problem here.

As far as the “passive” - “pending” issue, I suspect you’re not  
catching your record early enough in it’s aasm life.

These are all good questions to ask the rubyist-aasm folks - I just  
wouldn’t open the conversation with a !!!BUG REPORT!!! salvo  
iynwim 😉  
On Apr 21, 6:28 am, Joshua M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![josh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/45deac/32.png) [@josh](https://www.ruby-forum.com/u/josh)\
**Post date:** [April 22, 2009, 1:09am UTC](https://www.ruby-forum.com/t/acts-as-state-machine-bug-obj-save-doesnt-work/166002/8 "2009-04-22T01:09:18Z")

</div>

Actually, I didn’t forget. The model wasn’t available for reload  
because, by masking ActiveRecord#save with UsersController#save, there  
was nothing to reload.

But yes, version is probably going to make any more discussion  
difficult.

Here’s where I go:  
[GitHub - technoweenie/restful-authentication: inactive project](http://github.com/technoweenie/restful-authentication/tree/master).

This site is actively supported, maybe you should move there.
