CompanyユーザからStaffユーザを編集する方法（別モデルからの編集）

必要事項を記載して更新しようとすると、以下のようなことが起きた。
1. current_passwordを正しく入力しても不正とみなされる
1. emailアドレスを変更していない場合でも既に使用されているとしてバリデーションに引っかかる


上記を解消したコードは以下の通り（※備忘録なので詳細説明省く）

```app/controllers/staffs/registrations_controller.rb
# frozen_string_literal: true
class Staffs::RegistrationsController < Devise::RegistrationsController
  before_action :set_staff, only: %i(edit update destroy)
  before_action :authenticate_staff!, only: %i(edit update destroy)
  load_and_authorize_resource :class => 'Staff', except: %i(create update)
  before_action :configure_permitted_parameters, if: :devise_controller?

  def update
    authorize! :update, @staff
    if current_staff || (current_company && @staff.company_id == current_company.id)
      params[:staff][:service_ids].each do |service_id|
        service = Service.find(service_id)
        fee = params[:staff][:service_fees][service_id].presence || service.default_fee
        duration = params[:staff][:service_durations][service_id].presence || service.default_duration
        # serviceとのアソシエーション部分のみ先に保存
        @staff.update_or_create_available_service(service_id: service_id, fee: fee, duration: duration)
      end
      # ここから
      if current_staff
        self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
        bypass_sign_in resource, scope: resource_name if sign_in_after_change_password?
      elsif @staff.company_id == current_company.id
        self.resource = resource_class.to_adapter.get!(@staff.to_key)
      end
      # ここまで追記

      prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)
      resource_updated = update_resource(resource, account_update_params)
      yield resource if block_given?
      if resource_updated
        set_flash_message_for_update(resource, prev_unconfirmed_email)
        respond_with resource, location: after_update_path_for(resource)
      else
        clean_up_passwords resource
        set_minimum_password_length
        respond_with resource
      end
    else
      redirect_to root_path, alert: 'アクセス権限がありません。'
    end
  end

  protected

  def authenticate_staff!(opts = {})
    if action_name == 'update'
      @staff = Staff.new(staff_params)
    elsif !@staff
      @staff = Staff.find(params[:id])
    end
    unless staff_signed_in? || (company_signed_in? && @staff.company_id == current_company.id)
      redirect_to new_company_session_path, alert: 'アクセス権限がありません。'
    end
  end

  def set_staff
    begin
      if resource.present?
        @staff = Staff.find(resource.id)
      elsif params[:id]
        @staff = Staff.find(params[:id])
      end
    rescue ActiveRecord::RecordNotFound
      redirect_to root_path, alert: '指定されたスタッフが見つかりません。'
    end
  end

  def set_company
    @company = @staff.company
  end

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:id,
      :company_id,
      :name,
      :email,
      :position,
      :telephone,
      :postal_code,
      :prefecture,
      :city,
      :street_address,
      :description,
      :password,
      :password_confirmation,
      :current_password,
      service_ids: []])
    devise_parameter_sanitizer.permit(:account_update, keys: [:id,
      :company_id,
      :name,
      :email,
      :position,
      :telephone,
      :postal_code,
      :prefecture,
      :city,
      :street_address,
      :description,
      :password,
      :password_confirmation,
      :current_password, # ここを追記
      service_ids: []
      ])
  end

  def after_sign_up_path_for(resource)
    staff_path(resource)
  end

  def after_update_path_for(resource)
    staff_path(resource)
  end

  private

  def staff_params
    permitted_keys = [:id,
      :company_id,
      :name,
      :position,
      :telephone,
      :postal_code,
      :prefecture,
      :city,
      :street_address,
      :description,
      :password,
      :password_confirmation,
      :current_password,
      service_ids: [],
    ]
    # Emailの更新が必要な場合のみ `email` を追加
    permitted_keys << :email if email_needs_update?
    params.require(:staff).permit(permitted_keys)
  end

  def email_needs_update?
    params[:staff][:email].present? && params[:staff][:email] != Staff.find(params[:staff][:id]).email
  end

  def staff_signed_in?
    !current_staff.nil?
  end

  # 以下のメソッドをオーバーライド
  def update_resource(resource, params)
    if params[:password].blank? && params[:password_confirmation].blank?
      params.delete(:password)
      params.delete(:password_confirmation)
      resource.update(params.except(:current_password))
    else
      resource.update_with_password(params)
    end
  end

  # 以下のメソッドをオーバーライド
  def email_needs_update?
    params[:staff][:email].present? && params[:staff][:email] != Staff.find(params[:staff][:id]).email
  end
end

```

```app/models/staff.rb
class Staff < ApplicationRecord
  include PrefectureEnum
  devise :database_authenticatable, :registerable,
  :recoverable, :rememberable, :validatable
  has_many :reservations
  has_many :schedules, dependent: :destroy
  has_many :staff_business_hours, dependent: :destroy
  has_many :staff_replies, dependent: :destroy
  has_many :staff_reviews, dependent: :destroy
  has_many :available_services, dependent: :destroy
  has_many :services, through: :available_services
  has_many :time_tables, dependent: :destroy
  has_many :staffs, dependent: :destroy
  belongs_to :company

  # ここから
  attr_accessor :current_password
  validates :email, uniqueness: { case_sensitive: false }, if: :email_changed?
  validate :check_current_password, if: :password_present?
  # ここまで追記
  
  validates :name, presence: true
  enum position: { employee: 0, manager: 1, director: 2 }

  def update_or_create_available_service(service_id:, fee:, duration:)
    available_service = self.available_services.find_or_initialize_by(service_id: service_id)
    available_service.fee = fee
    available_service.duration = duration
    available_service.save
  end

  private

  # 追記。オーバーライド
  def password_present?
    self.password.present? || self.password_confirmation.present?
  end

  # 追記。オーバーライド
  def check_current_password
    unless Devise::Encryptor.compare(self.class, self.encrypted_password, current_password)
      errors.add(:current_password, 'is incorrect')
    end
  end

  # 追記。オーバーライド
  def email_must_be_unique
    # データベースに同じemailが存在するかどうかをチェック
    if Staff.where.not(id: self.id).exists?(email: self.email)
      errors.add(:email, "は既に使用されています")
    end
  end
end

```