環境
macOS: Big Sur Ver11.2.2
Rails: 6.0.0
Ruby: 2.6.5
この記事の目標
devise のデフォルトのユーザー編集画面ではパスワードの変更ができるが、現在のパスワードを入力しないとユーザー情報が編集できないようになっている。
そこで、
①現在のパスワードを入力しなくてもユーザー情報ができるようにする
②ユーザー編集のときだけモデルに設定しているパスワードのバリデーションを解除し、パスワード変更欄が空欄のままでもユーザー編集ができるようにする
の2点を実装することを目標とします。
現在のパスワードを入力不要にする
これについては多くの記事が出ています。以下が参考になります。
ユーザー編集時だけパスワードのバリデーションを解除する
まず、Userモデルのバリデーションは以下のとおり
class User < ApplicationRecord
has_many :menus
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :prefecture
belongs_to :category
has_one_attached :image
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
# パスワードは半角英数混合で8文字
validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8}\z/i }
with_options presence: true do
validates :shop_name
validates :address
validates :business_hours
validates :holiday
validates :image
validates :phone_number, format: { with: /\A0[1-9]\d{0,3}[-(]\d{1,4}[-)]\d{4}\z/ }
with_options numericality: { other_than: 0, message: 'を選択してください' } do
validates :category_id
validates :prefecture_id
end
end
end
真ん中あたりにパスワードカラムのバリデーションに関する記述があり、正規表現を使っているため自動的に presence: true の存在性のバリデーションが効いています。
これは新規登録時には必須なのですが、編集時にパスワードを変えずに他の項目だけ変更したい場合にバリデーションエラーのもとになってしまいます。
解決策(オプションを記述する)
上記のパスワードカラムに対するバリデーションに on: :create オプションを記述します。
これにより新規登録時のみバリデーションがかかるようになります!
参考:Railsガイド「onオプション」
class User < ApplicationRecord
(略)
# on: :createオプションを追記
validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8}\z/i }, on: :create
with_options presence: true do
validates :shop_name
validates :address
validates :business_hours
validates :holiday
validates :image
validates :phone_number, format: { with: /\A0[1-9]\d{0,3}[-(]\d{1,4}[-)]\d{4}\z/ }
with_options numericality: { other_than: 0, message: 'を選択してください' } do
validates :category_id
validates :prefecture_id
end
end
end
ただし、これではユーザー編集時にパスワードに関するバリデーション(今回は半角英数混合で8文字)がまったく効かなくなってしまい、「abc」とかでもパスワード設定できてしまいます。
そこで、今回はバリデーションの記述を2行に分け、allow_blank: true オプションを追記します。
ということで、最終的なモデルのコードはこんな感じ。
class User < ApplicationRecord
has_many :menus
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :prefecture
belongs_to :category
has_one_attached :image
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
# パスワードに関するバリデーションをcreateとupdateで別々に記述しました
validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8}\z/i }, on: :create
validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8}\z/i, message: 'は半角英数混合で8文字です' }, allow_blank: true, on: :update
with_options presence: true do
validates :shop_name
validates :address
validates :business_hours
validates :holiday
validates :image
validates :phone_number, format: { with: /\A0[1-9]\d{0,3}[-(]\d{1,4}[-)]\d{4}\z/ }
with_options numericality: { other_than: 0, message: 'を選択してください' } do
validates :category_id
validates :prefecture_id
end
end
def update_without_current_password(params)
if params[:password].blank? && params[:password_confirmation].blank?
params.delete(:password)
params.delete(:password_confirmation)
end
update(params)
end
end
これでユーザー編集時にパスワードの変更をしない場合は空欄のまま変更ができ、パスワードの変更をする場合は正規表現を適用することができました!
以上!