class User < ApplicationRecord attr_accessor :remember_token, :activation_token, :reset_token # before_save { self.email = email.downcase } # before_save { email.downcase! } before_save :downcase_email before_create :create_activation_digest validates :name, presence: true, length: { maximum: 50 } VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: true has_secure_password validates :password, presence: true, length: { minimum: 6 }, allow_nil: true def User.digest(string) cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost BCrypt::Password.create(string, cost: cost) end def User.new_token SecureRandom.urlsafe_base64 end def remember self.remember_token = User.new_token update_attribute(:remember_digest, User.digest(remember_token)) remember_digest end # 返回一个会话令牌,防止会话劫持 # 简单起见,直接使用记忆令牌 def session_token remember_digest || remember end class << self def digest(string) cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost BCrypt::Password.create(string, cost: cost) end def new_token SecureRandom.urlsafe_base64 end end # powered by metaprogramming def authenticated?(attribute, token) digest = send("#{attribute}_digest") return false if digest.nil? BCrypt::Password.new(digest).is_password?(token) end def forget update_attribute(:remember_digest, nil) end def activate # update_attribute(:activated, true) # update_attribute(:activated_at, Time.zone.now) update_columns(activated: true, activated_at: Time.zone.now) end def send_activation_email begin result = UserMailer.account_activation(self).deliver_now Rails.logger.info "Email sent successfully: #{result.inspect}" rescue => e Rails.logger.error "Failed to send email: #{e.message}" Rails.logger.error e.backtrace.join("\n") raise end end def create_reset_digest self.reset_token = User.new_token update_columns(reset_digest: User.digest(reset_token), reset_send_at: Time.zone.now) end def send_password_reset_email UserMailer.password_reset(self).deliver_now end def password_reset_expired? reset_send_at < 2.hours.ago end private def downcase_email # self.email = email.downcase email.downcase! end def create_activation_digest self.activation_token = User.new_token self.activation_digest = User.digest(activation_token) end end