1) PasswordResets emails user when requesting password reset

南笙酒味 提交于 2019-12-23 06:35:06

问题


I've been trying to add a password reset for users that forget their password. The users click on forgot password? on the sign up page. Then the user types their email and clicks reset password, which creates a token and sends an email with a link to reset their password. For the most part it works ONLY when the email box is blank or has exactly 6 random letter/numbers, but it doesn't work when a user puts in his email and clicks password reset, it brings up the error message:

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

By changing user.rb validates :password, presence: true, length: { minimum: 6 } validates :password_confirmation, presence: true

I have gotten different errors, is there anyway to exclude this validation from this Reset Password form

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

Ran into this error in video 275 How I Test. on 11:20

Failure/Error: click_button "Reset Password" ActiveRecord::RecordInvalid: Validation failed: Password can't be blank, Password is too short (minimum is 6 characters), Password confirmation can't be blank

     # ./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)>'

Finished in 13.66 seconds 95 examples, 1 failure

This is some of the code being used.

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

回答1:


At first glance, when resetting the password your code is trying to save a blank password (hence your error). Try debugging it one line at a time using logger.debug to try and find at what point your code nullifies the password before saving it. I haven't used the UserMailer, but it looks like the error is with the UserMailer.password_reset(self).deliver line. If you wrote the method, I'd look at debugging that first. If it was automated, try and debug the sections that set all the parameters for the mailer to generate the token and reset your password.

Hope this helps.




回答2:


In your send_password_reset method you're using:

save!

use instead

save!(validate: false)

and everything will work. The problem is that you're attempting to save the model and validations are interfering. You don't need to validate anything in the send_password_reset method since there is nothing generated from the user, so there's no danger of invalid information being saved to the database.



来源:https://stackoverflow.com/questions/10991138/1-passwordresets-emails-user-when-requesting-password-reset

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!