0

I've got Devise and omniauth gems. I more or less followed railscasts for multiple authentications so have Users and Authentications models.

I've managed to have a user update their own profile without a password when they have authentications.

class RegistrationsController < Devise::RegistrationsController
  def update_resource(resource, params)
    if current_user.authentications.empty?
      resource.update_with_password(account_update_params)
    else
      params.except("current_password")
      resource.update_without_password(account_update_params)
    end
  end
end

routes.rb:

devise_for :users, :controllers => {registrations: 'registrations'}, path_prefix: 'my'
resources :users

users/edit.html.haml

<%= bootstrap_form_for @user, html: {multipart: true} do |f|  %>
  ... 
<%= f.submit "Update" %>

users_controller.rb

def update
  @user = User.find(params[:id])

  Rails.logger.info(params.inspect)
  if @user.update_without_password(account_update_params)
    flash[:success] = "User updated by admin."
    redirect_to @user
  else
    Rails.logger.info(@user.errors.inspect) 
    flash[:alert] = "User update by admin failed to save"
    render 'edit'
  end

  private
  def account_update_params
    params.require(:user).permit(:email, :first_name, :last_name, :username, :dob,:city, :state, :zip, :password, :password_confirmation, :current_password)
  end

end

user.rb

def update_without_password(params, *options)
  params.delete(:password)
  params.delete(:password_confirmation)
  result = update_attributes(params, *options)
  clean_up_passwords
  result
end

Log file:

Started GET "/users/2/edit" for 127.0.0.1 at 2017-06-18 19:45:01 -0400
Processing by UsersController#edit as HTML
  Parameters: {"id"=>"2"}
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  Rendering users/edit.html.erb within layouts/application
  Rendered users/edit.html.erb within layouts/application (12.6ms)
  Rendered layouts/_shim.html.erb (0.3ms)
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?  [["id", 1], ["LIMIT", 1]]
  Rendered layouts/_sidenav.html.erb (1.0ms)
  Rendered layouts/_nav_top.html.erb (0.4ms)
  Rendered layouts/_notice.html.erb (0.3ms)
  Rendered layouts/_footer.html.erb (0.2ms)
Completed 200 OK in 193ms (Views: 190.3ms | ActiveRecord: 0.3ms)


Started PATCH "/users/2" for 127.0.0.1 at 2017-06-18 19:45:04 -0400
Processing by UsersController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"SwkF8C+P6iExhc1ju91C9xFgaR5GSKwy8KFJUaBtHCTKzEXmPIKhaAFHlfMO+6u4/UOM0y2IAAIkpfTsuBOX6g==", "user"=>{"first_name"=>"Bobby", "last_name"=>"", "username"=>"", "dob"=>"", "gender"=>"", "address1"=>"", "address2"=>"", "state"=>"", "zip"=>"", "email"=>"test@test.com"}, "commit"=>"Update", "id"=>"2"}
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
<ActionController::Parameters {"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"SwkF8C+P6iExhc1ju91C9xFgaR5GSKwy8KFJUaBtHCTKzEXmPIKhaAFHlfMO+6u4/UOM0y2IAAIkpfTsuBOX6g==", "user"=>{"first_name"=>"Bobby", "last_name"=>"", "username"=>"", "dob"=>"", "gender"=>"", "address1"=>"", "address2"=>"", "state"=>"", "zip"=>"", "email"=>"test@test.com"}, "commit"=>"Update", "controller"=>"users", "action"=>"update", "id"=>"2"} permitted: false>
   (0.1ms)  begin transaction
  Authentication Exists (0.1ms)  SELECT  1 AS one FROM "authentications" WHERE "authentications"."user_id" = ? LIMIT ?  [["user_id", 2], ["LIMIT", 1]]
  Authentication Exists (0.0ms)  SELECT  1 AS one FROM "authentications" WHERE "authentications"."user_id" = ? LIMIT ?  [["user_id", 2], ["LIMIT", 1]]
   (0.0ms)  rollback transaction
#<ActiveModel::Errors:0x007f9cf49d1758 @base=#<User id: 2, email: "test@test.com", created_at: "2017-06-18 16:05:51", updated_at: "2017-06-18 16:05:51", username: "", first_name: "Bobby", last_name: "", dob: nil, gender: "", address1: "", address2: "", city: nil, state: "", zip: "", admin: false, phone: nil>, @messages={:password=>["can't be blank"]}, @details={:password=>[{:error=>:blank}]}>
  Rendering users/edit.html.erb within layouts/application
  Rendered users/edit.html.erb within layouts/application (5.1ms)
  Rendered layouts/_shim.html.erb (0.3ms)
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?  [["id", 1], ["LIMIT", 1]]
  Rendered layouts/_sidenav.html.erb (0.9ms)
  Rendered layouts/_nav_top.html.erb (0.5ms)
  Rendered layouts/_notice.html.erb (0.3ms)
  Rendered layouts/_footer.html.erb (0.2ms)
Completed 200 OK in 199ms (Views: 188.4ms | ActiveRecord: 0.7ms)

The message @messages={:password=>["can't be blank"] is pointing to the answer, but everything I've tried isn't removing this requirement. I thought that Devise's update_without_password method would work out of the box.

I've even tried this at the top in user.rb.

validates :password, presence: true, length: {minimum: 5, maximum: 120}, on: :create
validates :password, length: {minimum: 5, maximum: 120}, on: :update, allow_blank: true

Thanks for the help SO!

sthoward
  • 81
  • 2
  • 13
  • Are you getting this error when you're trying to update a user profile from activeAdmin ? – Othmane El Kesri Jun 19 '17 at 01:37
  • I don't have activeAdmin setup. I have an Admin boolean on the user model. This error is only occurring when my Admin attempts to update a user (via the users_controller.rb), not when a user attempts to update themselves (via registrations_controller.rb). – sthoward Jun 19 '17 at 02:03

1 Answers1

0

Check out your UsersController. You are using except on your paramsand then using account_update_params in the conditional. except doesn't exactly delete the key and value from the Hash.

This is a helpful SO answer that should fix your situation here .

If that doesn't help I would follow Devise's existing guide on how to achieve this:

Make sure you follow the Devise guide for allowing users to edit their account without providing a password. I'm not sure what you are trying to do in your User model, are you trying to overwrite the Devise method?

If you are trying to overwrite the Devise method you should look at the method itself:

def update_without_password(params, *options)
  params.delete(:email)
  super(params)
end

If you are using this method, you should probably override this method to protect other attributes you would not like to be updated without a password.

Change your RegistrationsController to the match the docs:

def update_resource(resource, params)
  resource.update_without_password(params)
end

Then follow the remaining two steps and confirm your edited your view and routes.

If you need to make any changes authentication wise be sure to change the update_resource method.

jdgray
  • 1,863
  • 1
  • 11
  • 19
  • thanks for the help so far. I did check out that SO answer pointing to Devise wiki "How To: Allow users to edit their account without providing a password". My update_resource from registrations_controller.rb works for a user updating themself. My problem is an admin updating a user via users_controller.rb. Your comment on params.except - I tried something on this and will update OP. – sthoward Jun 19 '17 at 02:07
  • Why not use `current_user.authentications.present?` in your `UsersController`? – jdgray Jun 19 '17 at 02:09
  • current_user is an admin. The @user being edited is a different instance. So the current_user 's having or not having authentications should not matter to the instance being edited. – sthoward Jun 19 '17 at 02:13
  • Are you doing some sort of impersonation? Then instead of `current_user` use the `authentications` on the `@user` you are trying to change? – jdgray Jun 19 '17 at 02:18
  • Using byebug. Once users_controller.rb #update is hit and the flow goes through if @user.update_without_password(account_update_params), to the user.rb model def update_without_password(params, *options) method, I used byebug to just try and save a change to the user model (using self.first_name = "Test", then self.save!, and it's still giving me the :password=>["can't be blank" message. – sthoward Jun 19 '17 at 03:06