1)PasswordResets在请求密码重置时向用户发送电子邮件

时间:2012-06-12 05:48:29

标签: ruby ruby-on-rails-3 ruby-on-rails-3.2 forgot-password

我一直在尝试为忘记密码的用户添加密码重置功能。用户点击忘记密码?在注册页面上。然后,用户键入他们的电子邮件并单击重置密码,这将创建一个令牌并发送一封电子邮件,其中包含重置密码的链接。在大多数情况下,它只适用于电子邮箱是空白的或者只有6个随机字母/数字,但是当用户输入他的电子邮件并单击密码重置时它不起作用,它会显示错误消息:

**Validation failed: Password can't be blank
Password cant be blank, password is too short(6 min)**

更改 user.rb     验证:密码,在线状态:真实,长度:{最小值:6}     验证:password_confirmation,presence:true

我遇到了不同的错误,无论如何都要从此重置密码表单中排除此验证

app/models/user.rb:30:in `send_password_reset'
app/controllers/password_resets_controller.rb:7:in `create'

在我如何测试中遇到此错误。在11:20

失败/错误:click_button“重置密码”      ActiveRecord的:: RecordInvalid:        验证失败:密码不能为空,密码太短(最少6个字符),密码确认不能为空

     # ./app/models/user.rb:30:in `send_password_reset'
     # ./app/controllers/password_resets_controller.rb:7:in `create'
     # (eval):2:in `click_button'
     # ./spec/requests/password_resets_spec.rb:9:in `block (2 levels) in <top (required)>'

以13.66秒结束 95个例子,1个失败

这是一些正在使用的代码。

user.rb

    # == Schema Information
    #
    # Table name: users
    #
    #  id         :integer         not null, primary key
    #  name       :string(255)
    #  email      :string(255)
    #  created_at :datetime        not null
    #  updated_at :datetime        not null
    #

    class User < ActiveRecord::Base
     attr_accessible :name, :email, :password, :password_confirmation
     has_secure_password

      before_save { |user| user.email = email.downcase }
      before_save :create_remember_token

      validates :name, presence: true, length: { maximum: 50 }
      VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
      validates :email, presence:   true,
                format:     { with: VALID_EMAIL_REGEX },
                uniqueness: { case_sensitive: false }
      validates :password, presence: true, length: { minimum: 6 }
      validates :password_confirmation, presence: true

      def send_password_reset
        generate_token(:password_reset_token)
        self.password_reset_sent_at = Time.zone.now
        save!
        UserMailer.password_reset(self).deliver
      end

      def generate_token(column)
        begin
          self[column] = SecureRandom.urlsafe_base64
        end while User.exists?(column => self[column])
      end

      def self.search(search)
        if search
          find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
        else
          find(:all)
        end
      end

      private

        def create_remember_token
          self.remember_token = SecureRandom.urlsafe_base64
        end
    end

password_resets_controller.rb

            class PasswordResetsController < ApplicationController
      def new
      end

      def create
        user = User.find_by_email(params[:email])
        user.send_password_reset
        redirect_to root_url, :notice => "Email sent with password reset instructions."
      end

      def edit
        @user = User.find_by_password_reset_token!(params[:id])
      end
    end

password_resets_spec

    require 'spec_helper'

    describe "PasswordResets" do
      it "emails user when requesting password reset" do
        user = Factory(:user)
        visit signin_path
        click_link "password"
        fill_in "Email", :with => user.email
        click_button "Reset Password"
        current_path.should eq(root_path)
        page.should have_content("Email sent")
        last_email.to.should include(user.email)
      end
    end

user_spec.rb

    # == Schema Information
    #
    # Table name: users
    #
    #  id         :integer         not null, primary key
    #  name       :string(255)
    #  email      :string(255)
    #  created_at :datetime        not null
    #  updated_at :datetime        not null
    #

    require 'spec_helper'

    describe User do

      describe "#send_password_reset" do
        let(:user) { Factory(:user) }

        it "generates a unique password_reset_token each time" do
          user.send_password_reset
          last_token = user.password_reset_token
          user.send_password_reset
          user.password_reset_token.should_not eq(last_token)
        end

        it "saves the time the password reset was sent" do
          user.send_password_reset
          user.reload.password_reset_sent_at.should be_present
        end

        it "delivers email to user" do
          user.send_password_reset
          last_email.to.should include(user.email)
        end
      end

      before do
        @user = User.new(name: "Example User", email: "user@example.com", 
                 password: "foobar", password_confirmation: "foobar")
      end

      subject { @user }

      it { should respond_to(:name) }
      it { should respond_to(:email) }
      it { should respond_to(:password_digest) }
      it { should respond_to(:password) }
      it { should respond_to(:password_confirmation) }
      it { should respond_to(:remember_token) }
      it { should respond_to(:authenticate) }

      it { should respond_to(:admin) }
      it { should respond_to(:authenticate) }

      it { should be_valid }
      it { should_not be_admin }

      describe "with admin attribute set to 'true'" do
        before { @user.toggle!(:admin) }

        it { should be_admin }
      end

      describe "when name is not present" do
        before { @user.name = " " }
        it { should_not be_valid }
      end

      describe "when email is not present" do
        before { @user.email = " " }
        it { should_not be_valid }
      end

      describe "when name is too long" do
        before { @user.name = "a" * 51 }
        it { should_not be_valid }
      end

      describe "when email format is invalid" do
        it "should be invalid" do
          addresses = %w[user@foo,com user_at_foo.org example.user@foo.
                   foo@bar_baz.com foo@bar+baz.com]
          addresses.each do |invalid_address|
            @user.email = invalid_address
            @user.should_not be_valid
          end      
        end
       end

      describe "when email format is valid" do
        it "should be valid" do
          addresses = %w[user@foo.COM A_US-ER@f.b.org frst.lst@foo.jp a+b@baz.cn]
          addresses.each do |valid_address|
            @user.email = valid_address
            @user.should be_valid
          end      
        end
      end

      describe "when email address is already taken" do
        before do
          user_with_same_email = @user.dup
          user_with_same_email.email = @user.email.upcase
          user_with_same_email.save
        end

        it { should_not be_valid }
      end

      describe "email address with mixed case" do
        let(:mixed_case_email) { "Foo@ExAMPle.CoM" }

        it "should be saved as all lower-case" do
          @user.email = mixed_case_email
          @user.save
          @user.reload.email.should == mixed_case_email.downcase
        end
      end

      describe "when password is not present" do
        before { @user.password = @user.password_confirmation = " " }
        it { should_not be_valid }
      end

      describe "when password doesn't match confirmation" do
        before { @user.password_confirmation = "mismatch" }
        it { should_not be_valid }
      end

      describe "when password confirmation is nil" do
        before { @user.password_confirmation = nil }
        it { should_not be_valid }
      end

      it { should respond_to(:authenticate) }

      describe "with a password that's too short" do
        before { @user.password = @user.password_confirmation = "a" * 5 }
        it { should be_invalid }
      end

      describe "return value of authenticate method" do
        before { @user.save }
        let(:found_user) { User.find_by_email(@user.email) }

        describe "with valid password" do
          it { should == found_user.authenticate(@user.password) }
        end

       describe "with invalid password" do
          let(:user_for_invalid_password) { found_user.authenticate("invalid") }

          it { should_not == user_for_invalid_password }
          specify { user_for_invalid_password.should be_false }
        end
      end

      describe "remember token" do
        before { @user.save }
        its(:remember_token) { should_not be_blank }
      end
    end

2 个答案:

答案 0 :(得分:2)

在您使用的send_password_reset方法中:

save!

改为使用

save!(validate: false)

一切都会奏效。问题是您试图保存模型并且验证正在干扰。您不需要在send_password_reset方法中验证任何内容,因为用户没有生成任何内容,因此不存在将无效信息保存到数据库的危险。

答案 1 :(得分:0)

乍一看,重置密码时,您的代码正在尝试保存空白密码(因此您的错误)。尝试使用logger.debug一次调试一行,尝试找到您的代码在保存密码之前将密码置零的位置。我没有使用UserMailer,但看起来错误是UserMailer.password_reset(self).deliver行。如果你编写了这个方法,我先看一下调试方法。如果它是自动的,请尝试并调试为邮件程序设置所有参数的部分,以生成令牌并重置密码。

希望这有帮助。