Ich möchte Benutzerattribute ohne Passwort im Gerät aktualisieren. Der Fall ist wie folgt: Wenn Passwort und Passwortbestätigungsfelder nicht leer sind, muss ich einen Fehler entwickeln, und wenn sie leer sind, müssen andere Benutzerattribute aktualisiert werden. Wie könnte ich das mit Geräten machen?
Danke im Voraus!
ruby-on-rails
devise
Kriysna
quelle
quelle
Devise::RegistrationsController
s nicht zu überschreiben . Man kann sich den Wiki-Verlauf für frühere Versionen ansehen , aber seinen Rat berücksichtigen.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 einfach sicher, dass Sie dies vor
@user.attributes = params[:user]
oder was auch immer Sie in Ihrerupdate
Aktion verwenden, um die neuen Parameter aus dem Formular festzulegen.quelle
current_password
. Es wurde für den Fall entwickelt, dass alle Benutzerattribute (Name, E-Mail usw.) zusätzlich zu den Feldern zum Ändern des Kennworts angezeigt werden . Ohne eine solche Logik lässt Devise keine Aktualisierung von Attributen zu, wenn der Benutzer das Formular sendet, nachdem er andere Felder geändert hat, während die Kennwortfelder leer bleiben.Ich denke, mit Devise 3.2+ können Sie update_resource in Ihrem untergeordneten Controller einfach ü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
quelle
devise_for :users, controllers: {registrations: 'registrations'}
attr_accessor :current_password
mein Benutzermodell erweitern. Art von Hacks, die ich nicht mag. Sollte ich?params.delete :current_password
vorresource.update_without_password(params)
Ich habe dieses Problem wie folgt gelöst: Wenn das Formular mit einem Kennwort gesendet wird, muss das Feld current_password ausgefüllt oder das Formular ohne Kennwort und current_password aktualisiert werden
im Modell:
class User devise: bla-bla-bla attr_accessor :current_password end
In der Steuerung:
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
quelle
params [: user] [: password] funktioniert nicht in Schienen 6
Sie müssen params [: user] [: password] in params [: password] ändern.
Entfernen Sie [: user] in allen Parametern
Mein Quellcode ist unten
bevor Sie diesen Befehl ausführen
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
quelle
Ich löse dieses Problem mit meiner Schnittstelle. Es gibt zwei Möglichkeiten.
Deaktivieren Sie die Felder, wenn sie leer sind
Dieses Bit von jQuery deaktiviert die Felder, bevor das Formular gesendet wird, falls sie leer sind. Es erfordert ein bestimmtes Markup-Muster. Ü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"); } }); }); });
Geben Sie dem Benutzer ein Kontrollkästchen, um auszuwählen, ob er aktualisieren möchte
Eine andere Möglichkeit besteht darin, die Kennwortfelder aus dem Formular zu entfernen, wenn der Benutzer nicht angegeben hat, dass er sein Kennwort aktualisieren möchte. Hier ist das Beispiel für 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 kein Update der App selbst erforderlich. Sie senden nur die Felder, die Sie ändern möchten.
quelle
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 ein Passwort angeben. Der vorhandene Benutzer muss jedoch nur dann ein Kennwort angeben, wenn er entweder die Kennwort- oder die Kennwortbestätigungsattribute eingibt.
Weitere Einzelheiten 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 Anwesenheit prüfe (was für leere Zeichenfolgen false zurückgibt)
Hier ist eine Diskussion über meine Pull-Anfrage zu diesem Thema: https://github.com/plataformatec/devise/pull/3920
quelle
Wenn Sie die Kennwortänderung weiterhin unterstützen möchten, diese jedoch optional festlegen möchten, überprüfen Sie die Verfügbarkeit
current_password
als solche: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, fortfahren und das Kennwort aktualisieren. Andernfalls können Sie es ignorieren und ohne Kennwort aktualisieren.
quelle
Wenn Devise das aktuelle Kennwort nur überprüfen soll, wenn der Benutzer versucht, das Kennwort zu ändern ( dh , Sie können andere Attribute ändern, ohne das aktuelle Kennwort 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 vergiss nicht
devise_for :users, controllers: {registrations: 'registrations'}
in route.rb .
quelle
Es ist mehr Geschäftslogik, damit ich nicht zu viel Code in den Controller stecke. Ich schlage vor,
Devise::Models::Validatable#password_required?
in Ihrem Modell zu überschreiben :def password_required? new_record? || password.present? || password_confirmation.present? end
quelle
Als Problemumgehung in Ihr Benutzermodell einfügen
def password_required? encrypted_password.blank? || encrypted_password_changed? end
quelle
Für zukünftige Googler habe ich gerade 3 Stunden damit verbracht. Hier ist, was für mich funktioniert hat.
In meinem Benutzermodell entferne ich: validierbare und hinzugefügte Validierungsmethode für das Passwort und die Passwortbestätigung nur, wenn sie vorhanden sind:
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
Dann lösche ich in der Aktualisierungsmethode meines users_controller die Parameter password und password_confirmation, wenn sie leer sind
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
Einfach, schlicht, leicht und ohne Ruckeln mit Devises verschlungener Art, Dinge zu tun.
Gern geschehen.
quelle
Jeder, der 2020 besucht, ist die einfachste Lösung, die ich gefunden habe:
in
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
In route.rb:
devise_for :users, controllers: { registrations: 'users/registrations' }
Volle Anerkennung an: Masatoshi Nishiguchi
https://www.mnishiguchi.com/2017/11/24/rails-devise-edit-account-without-password/
quelle
Ich hatte genau das gleiche Problem und dies ist die Lösung, die ich gefunden habe und glaube mir, dass es funktioniert. Was ich getan habe, ist eine zweite
user_params
Methode zu erstellen und sieuser_params_no_pass
trotzdem zu benennen. Schauen Sie hier: Was hier passiert, ist, dass der Administrator ein Passwort bereitstellt, wenn das Passwort aktualisiert werden muss, andernfalls lassen Sie das Passwort leer. Wenn das Passwort leeruser_params_no_pass
ist, wird das Passwort anderweitig verwendetuser_params
. Ich hoffe das hilftdef 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
quelle
Ich finde diese geringfügige Abweichung vom obigen Code leichter zu befolgen:
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
quelle
Nach eingehender Untersuchung der oben genannten Möglichkeiten habe ich endlich eine Lösung gefunden, mit der Sie einige Attribute ohne Kennwort 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 route.rb
resources :users, only: [:show, :index, :edit, :update]
Ich habe Bearbeitungs- und Aktualisierungsmethoden in users_controller.rb vorgenommen
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. Der Devise Registration Controller wird komplett übersprungen, da ich mit ihm 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 von Aktien generierte Geräteansicht:
edit_user_registration_path(current_user)
Ich gebe zu, dass dies eine große Problemumgehung ist, aber keine der einfacheren Lösungen hat alle oben genannten Probleme gelöst.
quelle
Besser und kurzer Weg: Fügen Sie dem Parameter user_params Prüfparameter hinzu. 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
quelle
Um die Attribute für den Benutzer zu aktualisieren, müssen Sie Folgendes verwenden: current_password, um zu überprüfen, ob Ihr Benutzer das richtige current_password verwendet oder jemand Ihren Benutzer brechen 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 Müll aktualisieren
quelle