我想通過state_machine來讓我的用戶在Rails 3.1.3應用程序的註冊過程中有一個狀態。我試圖做一個非常簡單的案例,但我不能通過事件來改變它的狀態。在重新閱讀文檔sevreal時間後,我沒有發現什麼是錯的。rails state_machine不會改變狀態
我的用戶ActiveRecord的模式是:
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# email :string(255)
# created_at :datetime
# updated_at :datetime
# encrypted_password :string(255)
# salt :string(255)
# admin :boolean default(FALSE)
# notify_followers :boolean default(TRUE)
# state :string(255)
#
# MME per a utilitzar les Hash functions
require 'digest'
class User < ActiveRecord::Base
attr_accessor :password # MME nomes dona acces a la instance var @password que no es guarda a la BBDD
# MME si es posa, atributs (columnes) als que es podrà accedir via ActiveRecord
attr_accessible :name, :email, :password, :password_confirmation, :admin, :notify_followers
# MME validacions
validates :name, :presence => true,
:length=> {maximum: 50}
validates :email, :presence => true,
:format => { :with => /\A[\w+\-.][email protected][a-z\d\-.]+\.[a-z]+\z/i },
:uniqueness => { :case_sensitive => false}
validates :password, :presence => true,
:confirmation => true, # crea un atribut password_confirmation i a la vegada confirma que sigui igual que password
:length => { :within => 6..40 }
# validates :password_confirmation, :presence => true # MME aixo exigigeix que al crear es passi un :password_confirmation, doncs amb nomes
# l'anterior validator sol, pot crearse un usuari si no es passa :password_confirmation
before_save :encrypt_password
# MME a l'esborrar un User s'esborren tb els seus Micropost
has_many :microposts, :dependent => :destroy
# MME Afegim respostes als usuaris
has_many :replies, :class_name => 'Micropost',
:foreign_key => "in_reply_to",
:inverse_of => :replied_user,
:dependent => :destroy
# User com a seguidor (follower)
# te molts :relationships apuntant-lo amb la clau follower_id. Si el User s'elimina tots aquests Relationship tambe seran eliminats.
has_many :relationships, :foreign_key => "follower_id",
:dependent => :destroy
# te molts seguits via :relationships als que s'apunta via :followed_id (inferit gracies a :followed, que apunta a la vegada als User)
has_many :following, :through => :relationships,
:source => :followed
# User com a seguit (followed)
# te molts :reverse_relationships apuntant-lo amb la clau followed_id. Si el User s'elimina tots aquests Relationship tambe seran eliminats.
has_many :reverse_relationships, :class_name => "Relationship",
:foreign_key => "followed_id",
:dependent => :destroy
# te molts seguidors via :reverse_relationships als que s'apunta via :follower_id (inferit gracies a :follower, que apunta a la vegada als User)
has_many :followers, :through => :reverse_relationships
# Torna els microposts dels usuaris seguits per un user, per exemple:
# usr=User.find(12)
# usr.following_microposts
# (no el faig anar finalment: Micropost.from_users_followed_by(user) ho he implementat sense aquests metode perque
# em falten els microposts del propi user)
has_many :following_microposts, :through => :following,
:source => :microposts
# Si n'hi ha, te un password_reminder
has_one :password_reminder
# Torna l'User de l'email si el password es correcte
def self.authenticate(email, submited_pwd)
if usr = find_by_email(email)
usr.has_password?(submited_pwd) ? usr : nil
else
nil
end
end
# Torna l'User del id si el salt es correcte (s'utilitza per les sessions)
def self.authenticate_with_salt(id, salt)
user = find_by_id(id)
(user && user.salt == salt) ? user : nil
end
# verifica si el password correspon a l'User
def has_password?(submited_pwd)
self.encrypted_password == encrypt(submited_pwd)
end
def feed
#Micropost.from_users_followed_by self
# Microposts from
# self
# self.following
# self.replies
Micropost.not_messages.from_users_followed_by_or_in_reply_to self
end
# Is usr being followed by self?
def following? usr
following.include? usr
# MME segons el tutorial seria
#relationships.find_by_followed_id(followed)
end
def follow! usr
relationships.create! :followed_id => usr.id
end
def unfollow! usr
relationships.find_by_followed_id(usr.id).destroy if following?(usr)
end
def replies_to(usr, content)
microposts.create :content=>content, :in_reply_to=>usr.id, :private=>false
end
def sends_to(usr, content)
microposts.create :content=>content, :in_reply_to=>usr.id, :private=>true
end
def messages_to usr
microposts.messages.where(:in_reply_to => usr.id)
end
def messages_from usr
usr.microposts.messages.where(:in_reply_to => self.id)
end
def messages_to_or_from usr
Micropost.messages.between usr, self
end
alias conversation_with messages_to_or_from
# MME generates a unique login name for a user
def pseudo_login_name
name.downcase.split.join("_")+"_"+ id.to_s
end
# MME generates a password reminder if it doesn't yet exist
def generate_password_reminder
#PasswordReminder.find_or_create_by_user_id_and_token :user_id=>self.id,
# :token=>SecureRandom.hex(32)
create_password_reminder!(:token=>SecureRandom.hex(32)) unless password_reminder
end
# MME removes its password reminder if exists
def remove_password_reminder
password_reminder.delete if password_reminder
end
# finds a user from a token (password reminder to change password)
def self.find_by_token(token)
pr=PasswordReminder.find_by_token(token, :include=>:user)
pr.user if pr
end
# MME finds a user from a pseudo_login_name
# first tries to get it from an id
# last tries to get it from a name
def self.find_by_pseudo_login_name(pln)
nam=pln.split("_")
id = nam.last.to_i
if id>0 # First attempt: if it exists an id as the last part off the pln
User.find_by_id(id)
else # Second attempt: try to generate a name from a pln
User.find_by_name(nam.map(&:capitalize).join(" "))
end
end
## MME state_machine per a fer la inscripcio en passos
state_machine :initial => :pending do
event :email_confirm do
transition :pending => :email_confirmed
end
end
# FUNCIONS PRIVADES
private
def encrypt_password
self.salt = make_salt unless has_password?(password) # self.salt resets everytime user changes its password
self.encrypted_password = encrypt(password) # password refers to self.password
end
def make_salt
Digest::SHA2.hexdigest "#{Time.now.utc}--#{password}"
end
def encrypt(str)
Digest::SHA2.hexdigest "#{salt}--#{str}"
end
end
當然,我已經做了遷移,以使用戶以acomodate狀態機
$ rails g migration AddStateToUser state:string
$ rake db:migrate
,並檢查了該用戶真正響應來自rails控制檯的狀態屬性。
的問題出現了,當我試圖簡單地改變機器的狀態,想在這個控制檯會話日誌:
1.9.2-p290 :006 > u=User.find 1
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
=> #<User id: 1, name: "Marcel", email: "[email protected]", created_at: "2012-04-29 10:43:42", updated_at: "2012-04-29 10:43:42", encrypted_password: "d08c12c1cfb51fe5732f5e423b94dfdcaca1a1eb67821e3e37a...", salt: "78dfbecdfd4ffdd1fbcac5a878529b91a5200d563ebe3af23cf...", admin: false, notify_followers: true, state: "pendant">
1.9.2-p290 :007 > u.state
=> "pendant"
1.9.2-p290 :008 > u.email_confirm
(0.5ms) SELECT 1 FROM "users" WHERE (LOWER("users"."email") = LOWER('[email protected]') AND "users"."id" != 1) LIMIT 1
=> false
1.9.2-p290 :009 > u.state
=> "pendant"
,你可能會注意到,從最後的命令,我的用戶沒有改變他的狀態發送至:email_confirmed,因爲它已被提供。我也不明白這樣做的SQL查詢。這對我來說似乎很可疑。
更多內容。如果我像往常一樣嘗試更新用戶模型,則會出現同樣奇怪的SQL查詢並且不會更新模型。本會話記錄顯示:
1.9.2-p290 :001 > u=User.find 1
User Load (55.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
=> #<User id: 1, name: "Marcel Massana", email: "[email protected]", created_at: "2012-04-29 19:32:26", updated_at: "2012-04-29 20:44:10", encrypted_password: "2ef5fec3287e2b26600521488060f698abed387e18e395d1331...", salt: "fa4d3ebb44c00237b66c95cc75ed5d1cda3b6e1535082def2a8...", admin: true, notify_followers: true, state: "pending">
1.9.2-p290 :002 > u.update_attributes(:name=>"Marcel")
(0.1ms) SAVEPOINT active_record_1
(0.4ms) SELECT 1 FROM "users" WHERE (LOWER("users"."email") = LOWER('[email protected]') AND "users"."id" != 1) LIMIT 1
(0.1ms) ROLLBACK TO SAVEPOINT active_record_1
=> false
有人可以告訴我什麼是錯?任何提示?
(?當然我coud改變user.state =「email_confirmed」但當時爲什麼要使用state_machine)
問題出現在你的'email_confirm'中。它返回false,並且該查詢很奇怪。爲什麼它在做'用戶'。「id」!= 1'? –
好吧...... email_confirm在state_machine中定義,只需將它從:pendant更改爲:email_confirmed,但不會超過此值,正如您在帖子開頭處所看到的那樣。 –
你是否在使用一些創意會話,如設計? –