0

I have a two model setup with devise, users and profiles, with devise 4.2. I have implemented nested attributes with custom views as shown here: Rails 4.0 with Devise. Nested attributes Unpermited parameters

On my registrations/edit.html.haml view, when a user submits the form they must provide their current password by default. However, if the nested attributes are edited, and the password is not provided, the form will still update the nested attributes. How do I prevent this from happening?

registrations_controller.rb:

class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters

def new
    build_resource({})
    self.resource.profile = Profile.new
    respond_with self.resource
end

protected


def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:account_update) do |u|
        u.permit(<user fields>, profile_attributes: [<:profile_fields>])
    end
    devise_parameter_sanitizer.permit(:sign_up) do |u|
        u.permit(<user_fields>, profile_attributes: [<profile_fields>])
    end
end

end

registrations/edit.html.haml:

    .authform
  %h3
    Edit #{resource_name.to_s.humanize}
  = form_for(resource, :as => resource_name, :url => user_registration_path, :html => { :method => :patch, :role => 'form'}) do |f|
    = devise_error_messages!
    .form-group
      = f.label :email
      = f.email_field :email, class: 'form-control'
      - if devise_mapping.confirmable? && resource.pending_reconfirmation?
        %div
          Currently waiting confirmation for: #{resource.unconfirmed_email}
    %fieldset
      %p Leave these fields blank if you don't want to change your password.
      .form-group
        = f.label :password
        = f.password_field :password, :autocomplete => 'off', class: 'form-control'
      .form-group
        = f.label :password_confirmation
        = f.password_field :password_confirmation, class: 'form-control'
    %fieldset
      = f.fields_for :profile do |profile_fields|
        .form-group
          = profile_fields.label :a_field_1
          = profile_fields.number_field :a_field_1, min: 0, max: 8 
        .form-group
          = profile_fields.label :a_field_2
          = profile_fields.number_field :a_field_2, min: 0, max: 8
        .form-group
          = profile_fields.label :a_field_1
          = profile_fields.text_field :a_field_2, class: 'form-control'
    %fieldset
      %p You must enter your current password to make changes.
      .form-group
        = f.label :current_password
        = f.password_field :current_password, class: 'form-control'

    = f.submit 'Update', :class => 'button right'
sakurashinken
  • 2,851
  • 5
  • 23
  • 56

1 Answers1

0

It turned out that the root cause was an internal call to rails assign_attributes method which assigns nested attributes even if the password is invalid. The fix was to over-ride the update_resource method in the registrations controller with the following code

def update_resource(resource, params)incorrect
  unless resource.valid_password?(params[:current_password])
    resource.errors.add(:current_password, params[:current_password] ? :blank : :invalid)
    return resource
  end

  resource.update_with_password(params)
end

Which checks if the password is valid and stops the assignment process if it is not.

sakurashinken
  • 2,851
  • 5
  • 23
  • 56