Ich möchte Benutzerattribute ohne Passwort in devise aktualisieren. Der Fall ist wie, wenn Kennwort und Kennwortbestätigungsfelder nicht leer sind, dann brauche ich einen Fehler und wenn sie leer sind, müssen andere Benutzerattribute aktualisiert werden. Wie könnte ich das mit devise machen?
Danke im Voraus!
Ist es das, wonach du suchst? Aus dem Devise-Wiki
Benutzern erlauben, ihr Konto zu bearbeiten, ohne ein Passwort anzugeben
Es zeigt, wie es für Rails 3 und Rails 4 geht
=========================
Johns Lösung ist eine einfachere Alternative
Ich denke, das ist eine viel bessere Lösung:
if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
Dies verhindert, dass Sie den Devise-Controller ändern müssen, indem Sie einfach das Kennwortfeld aus der Formularantwort entfernen, wenn es leer ist.
Stellen Sie sicher, dass Sie diese before @user.attributes = params[:user]
oder was auch immer Sie in Ihrer update
-Aktion verwenden, um die neuen Parameter aus dem Formular festzulegen.
Ich denke, mit Devise 3.2+ können Sie einfach update_resource in Ihrem untergeordneten Controller überschreiben. Hier ist ein Beispiel für die ursprünglich gestellte Frage:
class MyRegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
end
Ich habe dieses Problem wie folgt gelöst: Wenn das Formular mit Kennwort übermittelt wird, müssen Sie das Feld current_password oder das Formular ohne Kennwort und current_password aktualisieren
im Modell:
class User
devise: bla-bla-bla
attr_accessor :current_password
end
Im Controller:
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
Ich löse dieses Problem mit meiner Schnittstelle. Es gibt zwei Möglichkeiten, wie es gehen kann.
Dieses jQuery-Bit deaktiviert die Felder, bevor das Formular übermittelt wird, falls sie leer sind. Es erfordert ein bestimmtes Auszeichnungsmuster, überprüfen Sie die Demo auf 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");
}
});
});
});
Eine weitere Option ist das Entfernen der Kennwortfelder aus dem Formular, wenn der Benutzer nicht angegeben hat, dass er sein Kennwort aktualisieren möchte. Hier ist das Beispiel auf 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();
});
In beiden Fällen ist keine Aktualisierung der App selbst erforderlich. Sie übermitteln nur die Felder, die Sie ändern möchten.
Ich überschreibe stattdessen #password_required? Methode innerhalb des Benutzermodells.
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
Wenn der Benutzer neu ist, muss er das Kennwort angeben. Ein vorhandener Benutzer muss das Kennwort jedoch nur angeben, wenn er entweder das Kennwort oder die Kennwortbestätigungsattribute eingibt.
Weitere Informationen finden Sie unter: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L33
Meine Implementierung ist fast identisch mit dem Original: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L53
außer dass ich auf Präsenz prüfe (was für leere Zeichenfolgen falsch ist)
Hier ist eine Diskussion über meine Pull-Anfrage in dieser Angelegenheit: https://github.com/plataformatec/devise/pull/3920
Wenn Sie die Kennwortänderung weiterhin unterstützen möchten, dies jedoch optional machen, überprüfen Sie die Verfügbarkeit von 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
Auf diese Weise können Sie, wenn das aktuelle_Kennwort vorhanden ist, das Kennwort aktualisieren und es sonst ignorieren und ohne Kennwort aktualisieren.
params [: user] [: password] funktioniert nicht in Rails 6
Sie müssen params [: user] [: password] in params [: password] ändern
Entferne [: user] in allen Parametern
mein Quellcode ist unten
bevor Sie diesen Befehl ausführen
Schienen erzeugen Geräte: Controller-Benutzer -c = Registrierungen
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
Wenn Sie möchten, dass Devise das aktuelle Passwort überprüft nur wenn der Benutzer versucht, das Passwort zu ändern (, bedeutet dies, dass Sie können andere Attribute ändern, ohne das aktuelle Passwort anzugeben ):
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
Auch in Ihrem Modell:
attr_accessor :current_password
Und nicht vergessen
devise_for :users, controllers: {registrations: 'registrations'}
in routes.rb.
Ich finde, dass diese geringfügige Variation des obigen Codes leichter zu folgen ist:
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
Nach eingehender Erkundung der oben genannten Möglichkeiten habe ich endlich eine Lösung gefunden, mit der Sie einige Attribute ohne Passwort aktualisieren können und einige mit:
Ich habe eine Ansicht für user/edit.html.erb mit dem folgenden Formular erstellt.
<%= 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 %>
Ich setze Routen in routen.rb
resources :users, only: [:show, :index, :edit, :update]
Ich habe Bearbeitungs- und Aktualisierungsmethoden in users_controller.rb erstellt
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
Ich habe diese Bearbeitungsansicht für Änderungen verwendet, für die kein Kennwort erforderlich war. Es wird der Geräteregistrierungscontroller vollständig übersprungen, da ich ihn mit verlinke
edit_user_path(current_user)
Ich habe auch die Parameter so eingestellt, dass E-Mail und Passwort hier nicht geändert werden können. Um das Passwort und die E-Mail-Adresse zu aktualisieren, verweise ich auf die erstellte Inventaransicht:
edit_user_registration_path(current_user)
Ich gebe zu, dass dies eine enorme Arbeit ist, aber keine der einfacheren Lösungen löste alle oben genannten Probleme.
Besser und kurzer Weg: Fügen Sie check params in den Block user_params ein. Zum Beispiel:
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
Ich hatte genau das gleiche Problem und dies ist die Lösung, die ich mir ausgedacht habe, und glaubt mir, dass es funktioniert. Was ich getan habe, ist, eine zweite user_params
-Methode zu erstellen und sie user_params_no_pass
zu nennen Geben Sie ein Kennwort ein, wenn das Kennwort aktualisiert werden muss. Andernfalls lassen Sie das Kennwort leer. Wenn das Passwort leer ist, wird der user_params_no_pass
verwendet, ansonsten user_params
. Ich hoffe das hilft
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
Es ist mehr Geschäftslogik, daher würde ich nicht zu viel Code in den Controller einfügen. Ich schlage vor, Devise::Models::Validatable#password_required?
in Ihrem Modell zu überschreiben:
def password_required?
new_record? || password.present? || password_confirmation.present?
end
um die Benutzerattribute zu aktualisieren, müssen Sie Folgendes verwenden: aktuelles_kennwort, um zu überprüfen, ob Ihr Benutzer das richtige aktuelle_kennwort verwendet oder ob jemand Ihren Benutzer auflösen möchte.
also in form:
= f.input :current_password,
hint: "we need your current password to confirm your changes",
required: true,
input_html: { autocomplete: "current-password" }
im Controller:
if your_user.valid_password?(params[:user][:current_password])
your_user.update_attributes(user_params.except(:current_password, :password, :password_confirmation))
end
in der ersten Zeile wird überprüft, ob Ihr Benutzer das richtige Kennwort sendet oder nicht. Anschließend können wir die Attribute ohne Datenverlust aktualisieren
Als Workaround fügen Sie Ihr Benutzermodell hinzu
def password_required?
encrypted_password.blank? || encrypted_password_changed?
end