Updating `User` attributes without requiring password

前端 未结 9 1646
醉酒成梦
醉酒成梦 2021-01-30 17:27

Right now, users can edit some their attributes without having to enter their password because my validations are set up like this:

validates :password, :prese         


        
相关标签:
9条回答
  • 2021-01-30 18:05

    I was having the same problem. I wasn't able to fix it with

    params[:user].delete(:password) if params[:user][:password].blank?
    

    I have only been able to get it to work by doing "update_attribute" on each item individually, e.g.

    if (  @user.update_attribute(:name, params[:user][:name])     && 
          @user.update_attribute(:email, params[:user][:email])   &&
          @user.update_attribute(:avatar, params[:user][:avatar]) &&
          @user.update_attribute(:age, params[:user][:age])       && 
          @user.update_attribute(:location, params[:user][:location]) &&
          @user.update_attribute(:gender, params[:user][:gender]) && 
          @user.update_attribute(:blurb, params[:user][:blurb])   )        
        flash[:success] = "Edit Successful."
        redirect_to @user
    else
      @title = "Edit user info"
      render 'edit'
    end
    

    which is clearly a total hack but its the only way I can figure it out without messing with the validations and deleting the password!

    0 讨论(0)
  • 2021-01-30 18:08

    I didn't realize the solution I gave you yesterday would lead to this problem. Sorry.

    Well, taking inspiration from devise, you should simply update your controller this way:

    def update
      params[:user].delete(:password) if params[:user][:password].blank?
      if @user.update_attributes(params[:user])
        flash[:success] = "Edit Successful."
        redirect_to @user
      else
        @title = "Edit user"
        render 'edit'
      end
    end
    
    0 讨论(0)
  • 2021-01-30 18:14

    I've been struggling with this and going around in circles for a while, so I thought I'd put my Rails 4 solution here.

    None of the answers I've seen so far meet my use case, they all seem to involve bypassing validation in some way, but I want to be able to validate the other fields and also the password (if present). Also I'm not using devise on my project so i can't make use of anything particular to that.

    Worth pointing out that it's a 2 part problem:

    Step 1 - you need to remove the password and confirmation field from the strong parameters if the password is blank like so in your controller:

    if myparams[:password].blank?
      myparams.delete(:password)
      myparams.delete(:password_confirmation)
    end
    

    Step 2 - you need to alter validation such that the password isn't validated if it's not entered. What we don't want is for it to be set to blank, hence why we removed it from our parameters earlier.

    In my case this means having this as the validation in my model:

    validates :password, :presence => true, :confirmation => true, length: {minimum: 7}, :if => :password
    

    Note the :if => :password - skip checking if the password is not being set.

    0 讨论(0)
  • 2021-01-30 18:16

    2017 answer:

    In Rails 5 as also indicated by Michael Hartl's tutorial, it's enought that you have something along these lines in your model:

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

    allow_nil: true is the key here which allows a user to edit his/her info without also requiring a password change too.

    At this point one might think that this will also allow empty user signups; However this is prevented by using the has_secure_password which automatically validates password presence but only the create method.

    This is a demo User model for illustration purposes:

    class User < ApplicationRecord
      attr_accessor :remember_token
      before_save { self.email = email.downcase }
      validates :name, presence: true, length: { maximum: 50 }
      VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
      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
      .
      .
      .
    end
    

    I have no clue how to do this with devise. My two cents.

    0 讨论(0)
  • 2021-01-30 18:22
    @user.username=params[:username]
    if @user.update_attribute(:email,params[:email])
    
      flash[:notice]="successful"
    else
      flash[:notice]="fail"
    end
    

    above code can update username and email field. because update_attribute can update dirty fields. but it is a pity, update_attribute would skip validation.

    0 讨论(0)
  • 2021-01-30 18:23

    This blog post demonstrates the principal of what you want to do.

    What is not shown, but may be helpful, is to add accessors to the model:

    attr_accessor   :new_password, :new_password_confirmation
    attr_accessible :email, :new_password, :new_password_confirmation
    

    and to provide all of the desired validation under the condition that the user has provided a new password.

      validates :new_password,  :presence => true, 
                                :length   => { :within => 6..40 }, 
                                :confirmation => true, 
                                :if       => :password_changed?
    

    Lastly, I would add a check to see if the encrypted_password has been set in order to determine if "password_changed?" in order to require a password on a new record.

      def password_changed?
        !@new_password.blank? or encrypted_password.blank?
      end
    
    0 讨论(0)
提交回复
热议问题