Joshua Muheim
2009-Apr-20  20:24 UTC
acts_as_state_machine: bug?! obj.save doesn''t work...
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
=> ''quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org'',
:password => ''quire'', :password_confirmation =>
''quire'' })
=> #<User id: nil, first_name: nil, last_name: nil, login:
"quire",
email: "quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org",
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:
"quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org", 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:
"quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org", 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
=> ''quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org'',
:password => ''quire'', :password_confirmation =>
''quire'' })
=> #<User id: nil, first_name: nil, last_name: nil, login:
"quire",
email: "quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org",
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:
"quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org", 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
-- 
Posted via http://www.ruby-forum.com/.
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...
Joshua Muheim
2009-Apr-21  09:04 UTC
Re: acts_as_state_machine: bug?! obj.save doesn''t work...
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 => ''quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org'', :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 => ''quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org'', :password => ''quire'', :password_confirmation => ''quire'' })=> #<User id: nil, first_name: nil, last_name: nil, login: "quire", email: "quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org", 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? -- Posted via http://www.ruby-forum.com/.
Rick Olson
2009-Apr-21  16:25 UTC
Re: acts_as_state_machine: bug?! obj.save doesn''t work...
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. -- Posted via http://www.ruby-forum.com/.
Joshua Muheim
2009-Apr-21  16:28 UTC
Re: acts_as_state_machine: bug?! obj.save doesn''t work...
Rick Olson 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... ;-) -- Posted via http://www.ruby-forum.com/.
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
=> ''quire-hcDgGtZH8xOIwRZHo2/mJg@public.gmane.orgm'',
:password => ''enquire'', :password_confirmation =>
''enquire'' })
=> #<User id: nil, login: "quire", name: "", email:
"quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org", 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:
"quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org", 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 Muheim
<rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org>
wrote:> RickOlson 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... ;-)
> --
> Posted viahttp://www.ruby-forum.com/.
Joshua Muheim
2009-Apr-21  21:59 UTC
Re: acts_as_state_machine: bug?! obj.save doesn''t work...
> You can now follow the sequence: > >>> record = User.new({ :login => ''quire'', :email => ''quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org'', :password => ''enquire'', :password_confirmation => ''enquire'' }) > => #<User id: nil, login: "quire", name: "", email: > "quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org", 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: > "quire-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org", 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... Attachments: http://www.ruby-forum.com/attachment/3603/restful_authentication.jpg -- Posted via http://www.ruby-forum.com/.
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: http://github.com/technoweenie/restful-authentication/tree/master. This site is actively supported, maybe you should move there.> > 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... > > Attachments:http://www.ruby-forum.com/attachment/3603/restful_authentication.jpg > > -- > Posted viahttp://www.ruby-forum.com/.