with tutorial framework español djangoproject desde con cero applications ruby-on-rails devise

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!



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