开发者

Updating `User` attributes without requiring password

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

validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :on => :create
validates :password, :confirmation => true, :length => { :within => 6..40 }, :on => :update, :unless => lambda{ |user| user.password.blank? } 

However, after a user does this, their password is deleted - update_attributes is updating their password to "". Here is my update definition:

def update

    if @user.update_attributes(params[:user])
        flash[:success] = "Edit Successful."
        redirect_to @user
    else
        @title = "Edit user"
        render 'edit'
    end
end

I've also tried using a different definition that uses update_attribute instead:

def save_ff
    @user = User.find(params[:id])
    @user.upda开发者_运维百科te_attribute(:course1, params[:user][:course1] )
    @user.update_attribute(:course2, params[:user][:course2] )
    @user.update_attribute(:course3, params[:user][:course3] )
    @user.update_attribute(:course4, params[:user][:course4] )
    redirect_to @user 
end 

But for some reason this is doing the same thing. How can I update some user attributes without changing the password? Thanks!


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


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


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.


# It smells

def update
  if params[:user][:password].blank?
    params[:user].delete :password
    params[:user].delete :password_confirmation
  end

  if @user.update_attributes(params[:user])
    flash[:success] = "Edit Successful."
    redirect_to @user
  else
    @title = "Edit user"
    render 'edit'
  end
end

# Refactoring

class User < ActiveRecord::Base
  ...
  def update_attributes(params)
    if params[:password].blank?
      params.delete :password
      params.delete :password_confirmation
      super params
    end
  end
  ...
end

def update
  if @user.update_attributes(params[:user])
    flash[:success] = "Edit Successful."
    redirect_to @user
  else
    @title = "Edit user"
    render 'edit'
  end
end

# And little better

class User < ActiveRecord::Base
  ...
  def custom_update_attributes(params)
    if params[:password].blank?
      params.delete :password
      params.delete :password_confirmation
      update_attributes params
    end
  end
  ...
end

def update
  if @user.custom_update_attributes(params[:user])
    flash[:success] = "Edit Successful."
    redirect_to @user
  else
    @title = "Edit user"
    render 'edit'
  end
end


2017 answer:

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

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

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

At this point people may think that this will also allow empty user signups; However this is prevented by using the has_secure_password which automatically validates password presence exclusively within 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

Unfortunately I've no clue how to make this work in devise. Cheers

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜