Deviseでパスワードなしでユーザー属性を更新したい。ケースは、パスワードとパスワードの確認フィールドが空白でない場合、エラーを考案する必要があり、それらが空白の場合、他のユーザー属性を更新する必要があるようなものです。どうすればdeviseでこれを行うことができますか?
前もって感謝します!
これはあなたが探しているものですか? Devise wikiから
ユーザーがパスワードを入力せずにアカウントを編集できるようにする
Rails 3 and Rails 4
=======================
ジョンのソリューション はより単純な代替手段です
私はこれがはるかに良い解決策だと思う:
if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
これにより、空白の場合にフォームの応答からパスワードフィールドを削除するだけで、Deviseコントローラーを変更する必要がなくなります。
必ずこれを使用してくださいbefore@user.attributes = params[:user]
またはupdate
アクションで使用して、フォームから新しいパラメーターを設定するもの。
Devise 3.2+では、サブクラス化されたコントローラーのupdate_resourceをオーバーライドすることができると思います。最初に尋ねられた質問の例を次に示します。
class MyRegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
end
私はこの問題を次のように解決しました:パスワードで送信するフォームの場合、current_passwordフィールドに記入するか、パスワードとcurrent_passwordなしで更新されたフォームが必要です
モデル内:
class User
devise: bla-bla-bla
attr_accessor :current_password
end
コントローラー内:
class Users::RegistrationsController < Devise::RegistrationsController
layout 'application'
def update
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
# custom logic
if params[:user][:password].present?
result = resource.update_with_password(params[resource_name])
else
result = resource.update_without_password(params[resource_name])
end
# standart devise behaviour
if result
if is_navigational_format?
if resource.respond_to?(:pending_reconfirmation?) && resource.pending_reconfirmation?
flash_key = :update_needs_confirmation
end
set_flash_message :notice, flash_key || :updated
end
sign_in resource_name, resource, :bypass => true
respond_with resource, :location => after_update_path_for(resource)
else
clean_up_passwords resource
respond_with resource
end
end
end
パスワードの変更を引き続きサポートしたいが、オプションにする場合は、current_password
など:
class MyRegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
if params[:current_password].blank?
resource.update_without_password(params.except(:current_password))
else
resource.update_with_password(params)
end
end
end
そうすれば、current_passwordが存在する場合、続行してパスワードを更新できます。それ以外の場合は無視し、パスワードなしで更新します。
私は自分のインターフェースでこの問題を解決します。 2つの方法があります。
このjQueryのビットは、フィールドが空の場合にフォームが送信される前にフィールドを無効にします。特定のマークアップパターンが必要です。 Codepenのデモ を確認してください。
$(".password-fields").each(function() {
var $fields, $form;
$form = $(this).parents("form");
$fields = $(this).find("input");
$form.on("submit", function() {
$fields.each(function() {
if ($(this).val() === "") {
$(this).attr("disabled", "disabled");
}
});
});
});
別のオプションは、ユーザーがパスワードの更新を指示していない場合に、フォームからパスワードフィールドを削除することです。例は CodePenで です。
$(".password-fields").each(function () {
var $fields, $button, html;
$fields = $(this);
$button = $fields.prev(".update-password").find("input");
html = $fields.html();
$button
.on("change", function () {
if ( $(this).is(":checked") ) {
$fields.html(html);
}
else {
$fields.html("");
}
})
.prop("checked", "checked")
.click();
});
どちらの場合でも、アプリ自体の更新は必要ありません。変更したいフィールドを送信するだけです。
代わりに#password_requiredをオーバーライドしますか?ユーザーモデル内のメソッド。
class User < ActiveRecord::Base
devise :database_authenticatable, :validatable #, ...
def password_required?
if respond_to?(:reset_password_token)
return true if reset_password_token.present?
end
return true if new_record?
password.present? || password_confirmation.present?
end
end
そのため、ユーザーが新しい場合、パスワードを指定する必要があります。ただし、既存のユーザーは、passwordまたはpassword_confirmation属性のいずれかを入力する場合にのみ、パスワードを指定する必要があります。
詳細については、以下を参照してください: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L
私の実装はオリジナルとほとんど同じです: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L5
存在を確認することを除いて(空白文字列に対してfalseを返します)
この問題に関するプルリクエストについての説明は次のとおりです。 https://github.com/plataformatec/devise/pull/392
params [:user] [:password]はRails 6で動作していません
params [:user] [:password]をparams [:password]に変更する必要があります
すべてのパラメーターの[:user]を削除
私のソースコードは以下です
このコマンドを実行する前に
Railsはdevise:controllersユーザーを生成します-c = registrations
class Users::RegistrationsController < Devise::RegistrationsController
# before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
protected
def update_resource(resource, params)
puts "params ===> #{params}"
if params[:password].blank? && params[:password_confirmation].blank?
params.delete(:password)
params.delete(:password_confirmation)
params.delete(:current_password)
resource.update_without_password(params)
else
super
end
end
end
Deviseに現在のパスワードをチェックさせたい場合、ユーザーがパスワードを変更しようとした場合のみ(つまり、can現在のパスワードを指定せずに他の属性を変更します):
class RegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
if params[:password].blank? && params[:password_confirmation].blank?
resource.update_without_password(params)
else
super
end
end
end
あなたのモデルでも:
attr_accessor :current_password
忘れないで
devise_for :users, controllers: {registrations: 'registrations'}
inroutes.rb.
回避策として、ユーザーモデルに入れます
def password_required?
encrypted_password.blank? || encrypted_password_changed?
end
上記のコードのこのわずかなバリエーションは、わかりやすいと思います。
def update
@user = User.find(params[:id])
method = if user_params[:password].blank?
:update_without_password
else
:update_with_password
if @user.send(method, user_params)
redirect_to @user, notice: 'User settings were saved.'
else
render :edit
end
end
上記の可能性を十分に検討した結果、パスワードなしでいくつかの属性を更新できるソリューションと、次のようにいくつかの属性を更新できるソリューションがようやく見つかりました。
次のフォームを含むuser/edit.html.erbのビューを作成しました。
<%= form_for(@user) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.submit "Save changes"%>
<% end %>
Routes.rbでルートを設定します
resources :users, only: [:show, :index, :edit, :update]
Users_controller.rbで編集および更新メソッドを作成しました
def edit
@user = current_user
end
def update
@user = current_user
if @user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to root_url
else
render 'edit'
end
end
def user_params
params.require(:user).permit(:name, :avatar, :whatsup)
end
パスワードを必要としない変更には、この編集ビューを使用しました。私はそれに登録するので、デバイス登録コントローラーを完全にスキップします
edit_user_path(current_user)
また、パラメーターを設定して、ここでメールとパスワードを変更できないようにします。パスワードと電子メールを更新するために、ストック生成デバイスビューにリンクします。
edit_user_registration_path(current_user)
これは大きな回避策であると認めますが、上記の問題をすべて解決できる単純なソリューションはありません。
より良い方法と短い方法:check paramsをuser_paramsブロックに追加します。例えば:
def user_params
up = params.require(:user).permit(
%i[first_name last_name role_id email encrypted_password
reset_password_token reset_password_sent_at remember_created_at
password password_confirmation]
)
if up[:password].blank? && up[:password_confirmation].blank?
up.delete(:password)
up.delete(:password_confirmation)
end
up
end
私はまったく同じ問題を抱えていましたが、これは私が思いついた解決策であり、それが機能すると信じています。私がやったのは、2番目のuser_params
メソッドと名前user_params_no_pass
とにかく見てみましょう:ここで何が起こっているのかは、パスワードを更新する必要があるときに管理者がパスワードを提供することです。パスワードが空白の場合、user_params_no_pass
が使用される、そうでなければuser_params
。それがお役に立てば幸いです
def update
if @user.valid_password?(params[:user][:password])
respond_to do |format|
if @user.update(user_params)
format.html { redirect_to @user, notice: 'User profile was successfully updated.' }
format.json { render :show, status: :ok, location: @user }
else
format.html { render :new }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
else
respond_to do |format|
if @user.update(user_params_no_pass)
format.html { redirect_to @user, notice: 'User profile was successfully updated without password.' }
format.json { render :show, status: :ok, location: @user }
else
format.html { render :edit }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
end
def destroy
@user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_user
@user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:user_name, :first_name, :middle_name, :last_name, :dob, :gender, :race, :hispanic, :leader, :mentor, :student, :email, :organization_id, :password, :opus,
:release_date, :days_to_release, :current_level, :is_active)
end
def user_params_no_pass
params.require(:user).permit(:user_name, :first_name, :middle_name, :last_name, :dob, :gender, :race, :hispanic, :leader, :mentor, :student, :email, :organization_id, :opus,
:release_date, :days_to_release, :current_level, :is_active)
end
それはよりビジネスロジックなので、コントローラーにあまり多くのコードを入れません。モデルでDevise::Models::Validatable#password_required?
をオーバーライドすることをお勧めします。
def password_required?
new_record? || password.present? || password_confirmation.present?
end
ユーザーの属性を更新するには、:current_passwordを使用して、「ユーザーが正しいcurrent_passwordを使用しているか、誰かがユーザーを破りたいか」を確認する必要があります。
のようにフォームで:
= f.input :current_password,
hint: "we need your current password to confirm your changes",
required: true,
input_html: { autocomplete: "current-password" }
コントローラー内:
if your_user.valid_password?(params[:user][:current_password])
your_user.update_attributes(user_params.except(:current_password, :password, :password_confirmation))
end
最初の行は、「ユーザーが正しいパスワードを送信するかどうか」をチェックし、その後、ゴミを出さずに属性を更新できます