こんばんは。
データアナリストの鈴木です。

と言いつつも、今日はRuby on Railsのお話になります。

今、Ruby on Railsで新しいプロジェクトを開発しています。
その中でユーザー認証機能を実装しているんですが、クライアントからの要望でユーザー情報の更新にいちいちパスワードを入力しないといけないのが面倒だとの話がでました。

セキュリティを考えたらあった方がいいかなと思うんですけどね。
でも説得は面倒そうなのですぐに諦めました。

ただ、調べたところパスワードなしで更新できる様にする方法は既にdeviseに実装されているとの事で、実際に実装してみました。具体的にはこんな感じ。

class Users::RegistrationsController < Devise::RegistrationsController
・・・略・・・
  protected
    def update_resource(resource, params)
      resource.update_without_password(params)
    end
end

あっさりパスワードなしでユーザー情報が更新できる様になりました。
ただ、この時は気がつかなかったのですが、実はこの実装によってパスワードの更新が出来なくなっていました。

しかし、案の定ネットで調べると答えがすぐに見つかりました。
原因は「update_without_password」にありました。
「update_without_password」はdeviseに元からあるメソッドですが、下記の様に実装されています。

def update_without_password(params, *options)
  if options.present?
    ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
      [Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
      (`options`) is deprecated and it will be removed in the next major version.
      It was added to support a feature deprecated in Rails 4, so you can safely remove it
      from your code.
    DEPRECATION
  end

  params.delete(:password)
  params.delete(:password_confirmation)

  result = update(params, *options)
  clean_up_passwords
  result
end

注目していただきたいのは、中段あたりでparamsからdeleteされているところです。:password、:password_confirmationともに削除されています。
これでは当然更新されませんね。

そこで解決方法としては こちら の記事を参考にさせていただきました。
ありがとうございました。
ただ、実際のコーディングでは元のコードが古い様だったので以下の様に変えています。(記事自体が2016年のものですし)

class Users::RegistrationsController < Devise::RegistrationsController
・・・略・・・
  protected
    def update_resource(resource, params)
      resource.update_without_current_password(params)
    end
end
class User < ApplicationRecord
・・・略・・・
  def update_without_current_password(params, *options)
    if params[:password].blank? && params[:password_confirmation].blank?
      params.delete(:password)
      params.delete(:password_confirmation)
    end

    result = update(params, *options)
    clean_up_passwords
    result
  end
end

これで無事にパスワードの更新ができる様になりました。
ちなみに、参考サイトに記載されていた下記部分はそもそもパラメータとして渡していないので削除しています。また、warnの部分も今回は削除しました。

params.delete(:current_password)

全部コードを読んでいるわけではないので、使い慣れていないgemはこういった思いがけないトラブルがあるなと反省しました。

もしコーディングに間違いなどあればご指摘ください。
本日も最後まで読んでいただき、ありがとうございました。