Je souhaite mettre à jour les attributs des utilisateurs sans mot de passe dans le système. Le cas est comme, si les champs mot de passe et confirmation de mot de passe ne sont pas vides alors j'ai besoin d'une erreur de conception et s'ils sont vides alors les autres attributs d'utilisateur doivent être mis à jour. Comment est-ce que je pourrais faire ceci avec la devise?
Merci d'avance!
Est-ce ce que vous cherchez? Du wiki Devise
Autoriser les utilisateurs à modifier leur compte sans fournir de mot de passe
Il montre comment faire pour Rails 3 et Rails 4
========================
La solution de John est une alternative plus simple
Je pense que c'est une bien meilleure solution:
if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
Cela vous évite de devoir modifier le contrôleur Devise en supprimant simplement le champ de mot de passe de la réponse au formulaire s'il est vide.
Veillez simplement à utiliser ce before@user.attributes = params[:user]
ou ce que vous utilisez dans votre action update
pour définir les nouveaux paramètres du formulaire.
Je pense qu'avec Devise 3.2+, vous pouvez simplement remplacer update_resource dans votre contrôleur sous-classé. Voici un exemple de la question posée à l'origine:
class MyRegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
end
J'ai résolu ce problème comme suit: si le formulaire est soumis avec un mot de passe, vous devez remplir le champ mot_de_passe ou le formulaire mis à jour sans mot de passe ni mot_de_passe
dans le modèle:
class User
devise: bla-bla-bla
attr_accessor :current_password
end
Dans le contrôleur:
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
Je résous ce problème avec mon interface. Cela peut aller de deux manières.
Ce bit de jQuery désactive les champs avant que le formulaire ne soit soumis au cas où ils seraient vides. Il faut un certain modèle de balisage, consultez la démo de 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");
}
});
});
});
Une autre option consiste à supprimer les champs de mot de passe du formulaire si l'utilisateur n'a pas indiqué qu'il souhaitait mettre à jour son mot de passe. Voici l'exemple sur 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();
});
Dans les deux cas, l'application ne nécessite aucune mise à jour. Vous ne faites que soumettre les champs que vous souhaitez modifier.
Je remplace plutôt #password_required? méthode à l'intérieur du modèle d'utilisateur.
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
Ainsi, si l'utilisateur est nouveau, il devra spécifier le mot de passe . Cependant, l'utilisateur ne devra spécifier le mot de passe que s'il remplit les attributs password ou password_confirmation.
Pour plus de détails, voir: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L33
Mon implémentation est presque identique à l'original: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L53
sauf que je vérifie la présence (qui renvoie false pour les chaînes vides)
Voici la discussion à propos de ma demande de retrait à ce sujet: https://github.com/plataformatec/devise/pull/3920
Si vous souhaitez toujours prendre en charge le changement de mot de passe mais le rendre facultatif, vérifiez la disponibilité de current_password
en tant que tel:
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
Ainsi, si le mot de passe current_password est présent, vous pouvez continuer et mettre à jour le mot de passe, sinon l'ignorer et le mettre à jour sans mot de passe.
params [: utilisateur] [: mot de passe] ne fonctionne pas dans Rails 6
Vous devez changer params [: utilisateur] [: motdepasse] en params [: motdepasse]
Supprimer [: utilisateur] dans tous les paramètres
mon code source est ci-dessous
avant d'exécuter cette commande
Les rails génèrent des informations: contrôleurs utilisateurs -c = inscriptions
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
Si vous voulez que Devise vérifie le mot de passe actuel uniquement lorsque l'utilisateur tente de changer de mot de passe (cela signifie que vous pouvez autres modifications sans fournir le mot de passe actuel):
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
Aussi dans votre modèle:
attr_accessor :current_password
Et n'oublie pas
devise_for :users, controllers: {registrations: 'registrations'}
dans routes.rb .
Je trouve cette légère variation du code ci-dessus plus facile à suivre:
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
Après une longue exploration des possibilités ci-dessus, j'ai finalement trouvé une solution qui vous permet de mettre à jour certains attributs sans mot de passe et d'autres avec:
J'ai créé une vue pour user/edit.html.erb avec le formulaire suivant.
<%= 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 %>
Je mets des routes dans routes.rb
resources :users, only: [:show, :index, :edit, :update]
J'ai créé et mis à jour des méthodes dans 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
J'ai utilisé cette vue de modification pour les modifications ne nécessitant pas de mot de passe. Il ignore complètement le contrôleur d’enregistrement de carte, car je me connecte à celui-ci avec
edit_user_path(current_user)
J'ai également paramétré les paramètres pour que l'email et le mot de passe ne puissent pas être changés ici. Pour mettre à jour le mot de passe et l'adresse e-mail, je fais un lien vers la vue d'ensemble générée par le stock:
edit_user_registration_path(current_user)
J'admets qu'il s'agit d'un travail énorme, mais aucune des solutions les plus simples n'a résolu tous les problèmes ci-dessus.
Meilleure façon: ajoutez les paramètres de vérification dans le bloc user_params. Par exemple:
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
J'ai eu exactement le même problème et c'est la solution que j'ai trouvée et croyez-moi que cela fonctionne . Ce que j'ai fait est de créer une deuxième méthode user_params
et l'ai nommée user_params_no_pass
. fournissez un mot de passe lorsque le mot de passe doit être mis à jour, sinon laissez le mot de passe vide. Lorsque le mot de passe est vide, le user_params_no_pass
est utilisé, sinon user_params
. J'espère que ça aide
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
C'est plus une logique métier donc je ne mettrais pas trop de code dans le contrôleur. Je suggère de remplacer Devise::Models::Validatable#password_required?
dans votre modèle:
def password_required?
new_record? || password.present? || password_confirmation.present?
end
pour mettre à jour les attributs pour l'utilisateur, vous devez utiliser: current_password, pour cocher la case "votre utilisateur utilise-t-il correctement le mot de passe actuel ou quelqu'un veut-il le casser"
donc sous forme:
= f.input :current_password,
hint: "we need your current password to confirm your changes",
required: true,
input_html: { autocomplete: "current-password" }
dans le contrôleur:
if your_user.valid_password?(params[:user][:current_password])
your_user.update_attributes(user_params.except(:current_password, :password, :password_confirmation))
end
la première ligne vérifie "votre utilisateur envoie-t-il le mot de passe correct ou non", et ensuite nous pourrons mettre à jour les attributs sans faille
Solution de contournement dans votre modèle utilisateur
def password_required?
encrypted_password.blank? || encrypted_password_changed?
end