ruby-on-rails - framework - tutorial django
Idear usuario de actualización sin contraseña (13)
Quiero actualizar los atributos de los usuarios sin contraseña. El caso es que, si los campos de confirmación de contraseña y contraseña no están en blanco, entonces necesito idear el error y si están en blanco, entonces otros atributos del usuario deben actualizarse. ¿Cómo podría hacer esto con el dispositivo?
¡Gracias por adelantado!
¿Es esto lo que buscas? De la wiki de Devise
Permitir a los usuarios editar sus cuentas sin proporcionar una contraseña
Muestra cómo hacerlo para rieles 3 y rieles 4
=======================
La solución de John es una alternativa más simple
Como una solución provisional en su modelo de Usuario
def password_required?
encrypted_password.blank? || encrypted_password_changed?
end
Creo que con Devise 3.2+ puedes anular update_resource en tu controlador subclasificado. Aquí hay un ejemplo para la pregunta formulada originalmente:
class MyRegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
end
Creo que esta es una solución mucho mejor:
if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
Esto evita que tenga que cambiar el controlador Devise simplemente quitando el campo de contraseña de la respuesta del formulario si está en blanco.
Solo asegúrese de usar esto antes @user.attributes = params[:user]
o lo que sea que use en su acción de update
para establecer los nuevos parámetros desde el formulario.
Después de mucha exploración de las posibilidades anteriores, finalmente encontré una solución que le permite actualizar algunos atributos sin una contraseña y algunos con:
Hice una vista para el usuario / edit.html.erb con el siguiente formulario.
<%= 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 %>
Establecí rutas en routes.rb
resources :users, only: [:show, :index, :edit, :update]
Hice editar y actualizar métodos en 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
Utilicé esta vista de edición para cambios que no requirieron una contraseña. Se saltea completamente el controlador de registro del diseño porque lo enlace a él con
edit_user_path(current_user)
También configuré los parámetros para que el correo electrónico y la contraseña no puedan modificarse aquí. Para actualizar la contraseña y el correo electrónico, me enlace a la vista de diseño generado:
edit_user_registration_path(current_user)
Admito que este es un gran trabajo, pero ninguna de las soluciones más simples resolvió todos los problemas anteriores.
En su lugar, anulo #password_required? método dentro del modelo de usuario.
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
Entonces, si el usuario es nuevo, se le pedirá que especifique la contraseña. Sin embargo, se requerirá que el usuario especifique la contraseña solo si rellena los atributos de contraseña o confirmación de contraseña.
Para obtener más información, consulte: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L33
Mi implementación es casi idéntica a la original: https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L53
excepto que compruebo la presencia (que devuelve falso para las cadenas en blanco)
Aquí hay un debate sobre mi solicitud de extracción sobre este asunto: https://github.com/plataformatec/devise/pull/3920
Encuentro esta ligera variación en el código anterior más fácil de seguir:
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
Es más lógica de negocios, así que no pondría demasiado código en el controlador. Sugiero invalidar Devise::Models::Validatable#password_required?
en tu modelo:
def password_required?
new_record? || password.present? || password_confirmation.present?
end
Resolví este problema de la siguiente manera: si el formulario se envía con contraseña, entonces es necesario rellenar el campo de contraseña actual o el formulario actualizado sin contraseña y contraseña_actual.
en modelo:
class User
devise: bla-bla-bla
attr_accessor :current_password
end
En el controlador:
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
Resuelvo este problema con mi interfaz. Hay dos maneras en que puede funcionar.
Deshabilita los campos si están vacíos
Este bit de jQuery deshabilita los campos antes de que el formulario se envíe en caso de que estén vacíos. Requiere un cierto patrón de marcado, consulte la demostración en 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");
}
});
});
});
Proporcione al usuario una casilla de verificación para seleccionar si desea actualizar
Otra opción es eliminar los campos de contraseña del formulario si el usuario no ha indicado que desea actualizar su contraseña. Aquí está el ejemplo en 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();
});
En cualquier caso, no es necesario actualizar la aplicación en sí. Solo está enviando los campos que desea cambiar.
Si aún desea admitir el cambio de contraseña pero hacerla opcional, verifique la disponibilidad de la contraseña current_password
como tal:
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
De esta forma, si la contraseña actual está presente, puede continuar y actualizar la contraseña; de lo contrario, ignórela y actualice sin contraseña.
Si desea que Devise compruebe la contraseña actual solo cuando el usuario intente cambiar la contraseña ( eso significa que puede cambiar otros atributos sin proporcionar la contraseña actual ):
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
También en tu modelo:
attr_accessor :current_password
Y no te olvides de
devise_for :users, controllers: {registrations: ''registrations''}
en routes.rb .
Tuve exactamente el mismo problema y esta es la solución que se me ocurrió y créanme que funciona. Lo que hice fue crear un segundo método user_params
y lo user_params_no_pass
todos modos, eche un vistazo: lo que está sucediendo aquí es que el administrador proporcionará una contraseña cuando la contraseña deba actualizarse, de lo contrario, deje la contraseña en blanco. cuando la contraseña está en blanco, user_params_no_pass
se usa else user_params
. Espero que eso ayude
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