I've been following Michael Hartl's rails tutorial and have been tackling the extension he suggests in Signup confirmation to get users to click on an emailed link to activate their account. To manage the activation I'm using the state_machine gem but when I try to activate a user account I get an error "Cannot transition state via :activate from :pending (Reason(s): Password is too short (minimum is 6 characters))". To me it seems as if the database operation which state_machine is implementing to update the state field is somehow causing validation associated with the user record (possibly associated with the has_secure_password method) to be triggered and to fail. I did come across another stackoverflow question here on the topic a year ago, but reading the comments on that question there didn't seem to be a resolution.
My user model (user.rb) code is below (it's basically the tutorial code in listing 6.29 plus the addition of a state machine). [Sorry, can't provide a link as stackoverflow is not allowing me more than 2 links!]
class User < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
before_save { email.downcase! }
validates :password, length: { minimum: 6, maximum: 50 }
has_secure_password
before_create :create_remember_token
state_machine initial: :pending do
state :pending, value: 0
state :active, value: 1
event :activate do
transition :pending => :active
end
event :deactivate do
transition :active => :pending
end
end
def initialize
super()
end
My database user table structure is:
create_table "users", force: true do |t|
t.string "name"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "password_digest"
t.string "remember_token"
t.boolean "admin", default: false
t.string "token"
t.integer "state"
end
In the rails console the state_machine code seems to be interpreting the values in the database ok, because I can get a user record and when I do user.can_activate? and user.can_deactivate? it's returning me what I expect. But when I try to do user.activate! or user.deactivate! I get the password too short error. Any suggestions as to how to address this?
I found the answer to this through changing the code to dispense with state_machine and update the state field in the database directly. I then discovered that all updates of the user record were causing the password validation to trigger and the password length error to appear (hence not a problem with state_machine). As described here the solution is to prevent the password validation from occurring if the password is not one of the attributes being updated by changing the "validates" line above to:
Once that is changed the state_machine functionality works fine.