[英]Devise update user without password
我想在沒有密碼的情況下更新用戶屬性。 情況就像,如果密碼和密碼確認字段不為空,那么我需要設計錯誤,如果它們為空,則需要更新其他用戶屬性。 我怎么能用設計做到這一點?
提前致謝!
我認為這是一個更好的解決方案:
if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
這可以防止您通過簡單地從表單響應中刪除密碼字段(如果它是空白的)來更改設計控制器。
請務必在@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 存在,您可以繼續並更新密碼,否則忽略它並在沒有密碼的情況下更新。
params[:user][:password] 在 rails 6 中不起作用
您必須將params[:user][:password]更改為params[:password]
刪除所有參數中的 [:user]
我的源代碼在下面
在運行此命令之前
rails generate devise:controllers users -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
我用我的界面解決了這個問題。 它有兩種方式。
如果字段為空,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#L33
我的實現與原始實現幾乎相同: https : //github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L53
除了我檢查是否存在(對於空白字符串返回 false)
這是關於我對此事的拉取請求的討論: https : //github.com/plataformatec/devise/pull/3920
任何在 2020 年訪問的人,這是我找到的最簡單的解決方案:
在registrations_controller.rb
:
class RegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
# Require current password if user is trying to change password.
return super if params["password"]&.present?
# Allows user to update registration information without password.
resource.update_without_password(params.except("current_password"))
end
end
在routes.rb中:
devise_for :users, controllers: {
registrations: 'users/registrations'
}
全部歸功於: Masatoshi Nishiguchi
https://www.mnishiguchi.com/2017/11/24/rails-devise-edit-account-without-password/
如果您希望設計僅在用戶嘗試更改密碼時檢查當前密碼(這意味着您可以在不提供當前密碼的情況下更改其他屬性):
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'}
在routes.rb 中。
這是更多的業務邏輯,所以我不會在控制器中放入太多代碼。 我建議覆蓋Devise::Models::Validatable#password_required?
在您的模型中:
def password_required?
new_record? || password.present? || password_confirmation.present?
end
作為您的用戶模型中的解決方法
def password_required?
encrypted_password.blank? || encrypted_password_changed?
end
對於未來的 Google 員工,我只花了 3 個小時,這對我有用。
在我的用戶模型中,我刪除了 :validatable 並添加了密碼和 password_confirmation 的驗證方法,僅當它們存在時:
class User < ApplicationRecord
devise :database_authenticatable, :registranable, recoverable, :rememberable
validates :password, length: { in: 6..128 }, if: lambda {self.password.present?}
validates_confirmation_of :password, if: lambda {self.password.present?}
end
然后在我的 users_controller 的更新方法中,如果密碼和 password_confirmation 參數為空,我將刪除它們
class UsersController > ApplicationController
def update
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
respond_to do |format|
if @user.update(user_params)
format.html { redirect_to @user, notice: 'User was successfully updated' }
else
format.html { render :edit }
end
end
end
end
使用 Devise 復雜的做事方式,簡單、朴素、輕松且不會手忙腳亂。
不客氣。
我遇到了完全相同的問題,這是我想出的解決方案,相信我是可行的。 我所做的是創建第二個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
我發現上面代碼的這種細微變化更容易理解:
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)
我承認這是一項巨大的工作,但沒有一個更簡單的解決方案可以解決上述所有問題。
更好更短的方法:將檢查參數添加到 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
要更新用戶的屬性,您需要使用: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
第一行檢查'你的用戶是否發送了正確的密碼',然后我們可以更新屬性而不是垃圾
如果你真的想在沒有 current_password 的情況下更新密碼,那么你需要使用用戶reset_password
方法
@user.reset_password(params[:user][:password], params[:user][:password_confirmation])
這是適用於所有場景的問題的完整工作解決方案:
if params.dig(:user, :password).blank?
updated = @user.update_without_password(params[:user].to_unsafe_hash)
else
if params.dig(:user, :current_password).nil?
@user.reset_password(params[:user][:password], params[:user][:password_confirmation])
updated = @user.update_without_password(params[:user].to_unsafe_hash)
else
updated = @user.update_with_password(params[:user].to_unsafe_hash)
end
bypass_sign_in(@user)
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.