NoMethodError:未定义的方法`password_reset_expired?'为零:NilClass

时间:2015-07-07 04:15:48

标签: ruby-on-rails ruby heroku railstutorial.org

我完成了Michael Hartl教程的一部分,我正在尝试将密码重置功能(从第10章)添加到我自己的应用程序中。我不想要激活功能,所以我没有添加它。但我确保添加与密码重置邮件程序相关的部分(例如,经过验证的方法)。

当我运行rake时,这就是我得到的:

ERROR["test_password_resets", PasswordResetsTest, 2015-07-06 17:12:16 -0700]
 test_password_resets#PasswordResetsTest (1436227936.11s)
NoMethodError:         NoMethodError: undefined method `password_reset_expired?' for nil:NilClass
            app/controllers/password_resets_controller.rb:60:in `check_expiration'
            test/integration/password_resets_test.rb:26:in `block in <class:PasswordResetsTest>'
        app/controllers/password_resets_controller.rb:60:in `check_expiration'
        test/integration/password_resets_test.rb:26:in `block in <class:PasswordResetsTest>'

  33/33: [=================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.10830s
33 tests, 83 assertions, 0 failures, 1 errors, 0 skips

这是我的密码重置控制器:

class PasswordResetsController < ApplicationController
  before_action :get_user,   only: [:edit, :update]
  before_action :valid_user, only: [:edit, :update]
  before_action :check_expiration, only: [:edit, :update]

  def new
  end

  def create
    @user = User.find_by(email: params[:password_reset][:email].downcase)
    if @user
        @user.create_reset_digest
        @user.send_password_reset_email
        flash[:info] = "An email was sent to " + @user.email + " with password reset instructions."
        redirect_to login_url
    else
        flash.now[:danger] = "Hmm. We don't recognize that email. Make sure you signed up with this email."
        render 'new'
    end
  end

  def edit
  end

  def update
    if params[:user][:password].empty?
      flash.now[:danger] = "Uh oh. Your password can't be empty."
      render 'edit'
    elsif @user.update_attributes(user_params)
      log_in @user
      flash[:success] = "Success! Your password has been reset!"
      redirect_to @user
    else
      render 'edit'
    end
  end

  private

  def user_params
    params.require(:user).permit(:password, :password_confirmation)
  end

  #BEFORE FILTERS

  def get_user
    @user = User.find_by(email: params[:email])
  end

  # Confirms a valid user.
  def valid_user
    if (@user && @user.authenticated?(:reset, params[:id]))
      redirect_to root_url
      puts("Either I don't exist or I'm not authenticated.")
    end
  end

  # Checks expiration of reset token.
  def check_expiration
    if @user.password_reset_expired?
      flash[:danger] = "Uh oh! Your password reset has expired. Please request a new password reset."
      redirect_to new_password_reset_url
    end
  end

end

这是我的用户模型:

class User < ActiveRecord::Base
    attr_accessor :remember_token, :reset_token
    before_save { email.downcase! }


    validates :name, presence: true, length: { maximum: 50 }

    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i #Set valid email regex to be used
    validates :email, presence: true, length: { maximum: 255 }, format: {with: VALID_EMAIL_REGEX}, uniqueness: { case_sensitive: false}

    has_secure_password
    validates :password, presence: true, length: { minimum: 6 }, allow_nil: true

    # Returns the hash digest of the given string.
    def User.digest(string)
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                BCrypt::Engine.cost
    BCrypt::Password.create(string, cost: cost)
    end

    # Returns a random token.
    def User.new_token
        SecureRandom.urlsafe_base64
    end

    # Remembers a user in the database for use in persistent sessions.
    def remember
        self.remember_token = User.new_token
        update_attribute(:remember_digest, User.digest(remember_token))
    end

    # Returns true if the given token matches the digest.
    def authenticated?(attribute, token)
      digest = send("#{attribute}_digest")
      return false if digest.nil?
      BCrypt::Password.new(digest).is_password?(token)
    end

    # Forgets a user.
    def forget
        update_attribute(:remember_digest, nil)
    end

    #PASSWORD RESET
      def create_reset_digest
        self.reset_token = User.new_token
        update_attribute(:reset_digest, User.digest(reset_token))
        update_attribute(:reset_sent_at, Time.zone.now)
      end

      def send_password_reset_email
        UserMailer.password_reset(self).deliver_now
      end

      # Returns true if a password reset has expired.
      def password_reset_expired?
        reset_sent_at < 2.hours.ago
      end

end

我已经检查了我的拼写,结束了一遍又一遍,但即使我更改了该功能的名称也没有任何区别。发生了什么事?

顺便说一句,当我实际尝试在localhost:3000中使用密码重置时,它表示已发送确认电子邮件(但我没有收到一封,因为我认为这是localhost的一部分)。然后,当我访问邮件程序预览,并使用重置密码,它工作正常。但是在生产中(在Heroku上),如果我尝试输入我的电子邮件以收到确认电子邮件,我只会得到一个错误页面--500。为什么会发生这种情况?

如果我需要添加更多详细信息,请与我们联系。

1 个答案:

答案 0 :(得分:2)

如果找不到您的用户(例如,没有用户使用给定的电子邮件)...当您尝试检查其过期时会发生什么?

提示:查看您在valid_user中的操作,了解您应该在check_expiration

中执行的操作示例