3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【devise】user情報の編集がやっとできた話〜もうパスワードなんていらない〜

Posted at

なんの話?

deviseを導入してuser情報を管理していたが、編集をしようと思ったら一筋縄でいかなかった話です。

自分がやったこと

  • usersコントローラーにeditアクション、updateアクションをそれぞれ記述
  • viewファイルを変更
users_controller.rb
  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
      redirect_to root_path, dark: 'ユーザー情報の編集ができました'
    else
      flash[:danger] = 'ユーザー情報の編集ができませんでした'
      render :edit
    end
  end

すごーく単純な作業だからすぐできると思っていた。
その結果。
cb06073e6877eba08feabd88aceb6d99.png

色々と調べてみたところ、deviseのコントローラーを新しく追加すればいけるようだったのでやってみる。

1・まずはコントローラーを作成

% rails g devise:controllers users

⬇️⬇️⬇️実行結果⬇️⬇️⬇️

Running via Spring preloader in process 7028
      create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb
      create  app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================

Some setup you must do manually if you haven't yet:

  Ensure you have overridden routes for generated controllers in your routes.rb.
  For example:

    Rails.application.routes.draw do
      devise_for :users, controllers: {
        sessions: 'users/sessions'
      }
    end

===============================================================================

2・作成したregistrations_controllerに記述

registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
 before_action :configure_account_update_params, only: [:update]

  protected

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

  def configure_account_update_params
    devise_parameter_sanitizer.permit(:account_update,
      keys: [:nickname, :gender_id, :profile, :genre_id])⬅️keys:の中身はカラム名に
  end
end

devise_parameter_sanitizer.permit(:account_update,   keys: [:nickname, :gender_id, :profile, :genre_id])
このkeys:の部分には自分のDBのカラム名を設定。
email、password、password_confirmationは書かない。
アカウントをupdate(編集)する時に、どのデータの受け取りを許可させるか指定する。

3・ルーティングに記述

routes.rb
Rails.application.routes.draw do

  devise_for :users, controllers: {
    registrations: 'users/registrations'
  }

〜以下略〜

devise_for :usersの部分に追加。

4・userモデルに記述

user.rb
class User < ApplicationRecord
 
〜中略〜

  PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i.freeze
  #on: :create ➡️ createアクションの時にだけvalidatesをかける
  validates :password, format: { with: PASSWORD_REGEX }, on: :create
  validates :password, confirmation: true, on: :create

end

passwordとpassword_confirmationの部分にon: :createを追記。
createアクションを経由するときだけにバリデーションをかけるようにする。
つまりupdateアクションの時にpasswordを必要としない(バリデーションをかけない)ように変更。

5・viewファイルを変更

入力フォームを空にして送信すると突然見たことがないviewファイルが読み込まれる。
app> views> devise> registration> edit.html.erb
どうやらこのファイルを読み込んでいるようなのでviewファイルを変更する。
app> views> users> edit.html.erb
ここに作ったものをそのままコピペ。
この時にemail、password、password_confirmationの項目は表示させないようにするため削除しておく。

6・flashメッセージの設定

users.controller.rb
  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
      redirect_to root_path, dark: 'ユーザー情報の編集ができました'
    else
      flash[:danger] = 'ユーザー情報の編集ができませんでした'
      render :edit
    end
  end

usersコントローラーを経由しなくなりflashメッセージが出なくなってしまったので、registrations_controllerに記述する。

registrations_controller.rb
〜略〜

  # PUT /resource
  # def update
  #   super
  # end

〜略〜

updateアクションはデフォルトでこうなっていた。
superで呼び出している内容は

  def update
    self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
    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)
      bypass_sign_in resource, scope: resource_name if sign_in_after_change_password?

      respond_with resource, location: after_update_path_for(resource)
    else
      clean_up_passwords resource
      set_minimum_password_length
      respond_with resource
    end
  end

これを書き換えたらこうなった。

registrations_controller.rb
  # PUT /resource
  def update
    self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
    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
      redirect_to @user, dark: 'ユーザー情報の編集ができました'
      bypass_sign_in resource, scope: resource_name if sign_in_after_change_password?
    else
      flash[:danger] = 'ユーザー情報の編集ができませんでした'
      clean_up_passwords resource
      set_minimum_password_length
      respond_with resource
    end
  end

elseの部分は加えるだけで良かったがifのほうはそのまま加えると
AbstractController::DoubleRenderError in Users::RegistrationsController#update
というエラーが出て、ダブルレンダリングしてるよと怒られてしまった。
該当の部分を削除して完成し、ようやくやりたいことが実現できた。
修正部分などありましたらご指摘下さい。

参考にさせて頂きました

@coxcoa
Deviseでユーザー情報の編集

[heartcombo/devise]GitHub

ありがとうございました。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?