Devise 3 (rails 4) can't update user without password
Solution 1
The password validation is coming from the user model:
validates :password, presence: true
The solution is to only validate presence on create and allow_blank on update:
validates :password, presence: true, length: {minimum: 5, maximum: 120}, on: :create
validates :password, length: {minimum: 5, maximum: 120}, on: :update, allow_blank: true
Solution 2
As of 2014, you can simply override a protected method and do:
class RegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
end
Solution 3
You can use @user.update_without_password(user_params)
method to update your other fields.
For example, I have this in my custom users_controller.rb. I update with remote call (ajax).
#users_controller.rb
def update
respond_to do |format|
if needs_password?(@user, user_params)
if @user.update_with_password(user_params_password_update)
flash[:success] = 'User was successfully updated. Password was successfully updated'
format.js {render 'update'}
else
error = true
end
else
if @user.update_without_password(user_params)
flash[:success] = 'User was successfully updated.'
format.js {render 'update'}
else
error = true
end
end
if error
flash[:error] = @user.errors.full_messages.join(', ')
format.js {render json: @user.errors.full_messages, status: :unprocessable_entity}
end
end
end
private
def needs_password?(user, user_params)
!user_params[:password].blank?
end
def user_params
params[:user].permit(:email, :password, :password_confirmation, :username, :full_name)
end
#Need :current_password for password update
def user_params_password_update
params[:user].permit(:email, :password, :password_confirmation, :current_password, :username, :full_name)
end
Solution 4
The key is in this "user_params[:password].blank?". The next is a example of the code:
def update
if user_params[:password].blank?
params = user_params_without_password
else
params = user_params
end
respond_to do |format|
if @user.update(params)
format.html { redirect_to @user, notice: t(:user_update) }
format.json { render :show, status: :ok, location: @user }
else
format.html { render :edit }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
private
def set_user
@user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:email, :username, :first_name, :last_name, :admin, :locked, :password)
end
def user_params_without_password
params.require(:user).permit(:email, :username, :first_name, :last_name, :admin, :locked)
end
Hope you help
Solution 5
I went round in circles on this for ages. The answers are all in validatable as suggested by mrstif above. If you use the validatable module Devise works out of the box (with configuration options) allowing you to update user details without supplying a password so be very careful about rolling your own password validations.
Darcbar
Updated on July 02, 2022Comments
-
Darcbar almost 2 years
I'm trying to update a user without having to provide a password, but approaches that worked on older devise/rails versions no longer work with devise 3 and rails 4 strong parameters.
I'm using my user_controller to update but I have also tried using a custom devise registration controller with devise_parameter_sanitizer, without success.
The form does not require a password (has no password field) and the user_controller handling the update looks like so:
# PATCH/PUT /users/1 def update if user_params[:password].blank? Rails.logger.info "entered if statement" user_params.delete :password user_params.delete :password_confirmation Rails.logger.info(user_params.inspect) end @user = current_user if @user.update(user_params) redirect_to @user, notice: 'User was successfully updated.' else Rails.logger.info(@user.errors.inspect) render action: 'edit' end end private def user_params params.require(:user).permit(:screen_name, :full_name, :email, :about, :location, :profile_pic, :password, :password_confirmation, :current_password) end
.. the log after a submit looks like:
Started PATCH "/users/13" for 127.0.0.1 at 2013-05-29 11:18:18 +0100 Processing by UsersController#update as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"20avah2OzaOVubAiam/SgvbYEQ4iijEWQqmNo7xD4rY=", "user"=>{"screen_name"=>"Darcbar", "full_name"=>"Barry Darcy", "about"=>"", "location"=>"", "website_url"=>"", "twitter_username"=>"", "email"=>"[email protected]"}, "commit"=>"Save changes", "id"=>"13"} User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 13 ORDER BY "users"."id" ASC LIMIT 1 Entered if statement... {"screen_name"=>"Darcbar", "full_name"=>"Barry Darcy", "email"=>"[email protected]", "about"=>"", "location"=>"", "twitter_username"=>"", "website_url"=>""} (0.2ms) BEGIN User Exists (0.8ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = '[email protected]' AND "users"."id" != 13) LIMIT 1 (0.2ms) ROLLBACK #<ActiveModel::Errors:0x007fedf45bb640 @base=#<User id: 13, username: "darcbar", full_name: "Barry Darcy", about: "", location: "", email: "[email protected]", encrypted_password: "$2a$10$Mb4zsRPPqZ9CYz0zdLMBU.62NyIk/T8s6Zw/uRTwWov3...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 9, current_sign_in_at: "2013-05-28 17:51:20", last_sign_in_at: "2013-05-28 16:42:52", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", authentication_token: nil, created_at: "2013-05-27 14:03:41", updated_at: "2013-05-28 17:51:20", screen_name: "Darcbar", profile_pic_file_name: nil, profile_pic_content_type: nil, profile_pic_file_size: nil, profile_pic_updated_at: nil>, @messages={:password=>["please enter a password with at least 5 characters", "please enter a password with at least 5 characters"]}> Rendered users/edit.html.haml within layouts/application (3.0ms) Rendered partials/head/_user_options.haml (1.8ms) Completed 200 OK in 74ms (Views: 12.1ms | ActiveRecord: 1.7ms)
Does anyone know why the password errors are present?
-
Darcbar almost 11 yearsThanks szines, unfortunately the log displays exactly the same when using update_without_password (password errors present).
-
Zoltan almost 11 yearsMuch more simpler. In your case it is perfect... (Unfortunately, I have to watch that a user wants to update password or just wants to modify other details without password... But I will give a try for
allow_blank
...) Thanks! -
Chris over 10 yearsThis indeed solves the problem. Keeping it DRY this seems to be enough:
validates_presence_of :password, on: :create
andvalidates_length_of :password, minimum: 5, maximum: 120, allow_blank: true
. validates_presence seems to take precedence over allow blank. -
mrstif over 9 yearsNOTE: This solution allows the password to be empty if you're updating it. To solve this simply do it as Devise does it in the Validatable module
-
Amin Ariana about 9 yearsIt goes in the controllers folder. It's just a regular controller, like any other.
-
Betty St almost 9 yearsThis is also the official solution in the devise wiki: github.com/plataformatec/devise/wiki/…
-
riley almost 9 yearsDon't forget to add to your routes
devise_for :users, controllers: {registrations: 'registrations'}