Malcolm says (10 July 2013): My implementation.

Extra field in views/users/_form.html.erb:
  <% if params[:action] == 'edit' || 'update' %>
  <div class="field">
    <%= f.label :current_password, 'Current password:' %>
    <%= f.password_field :current_password, size: 40 %>
  </div>
  <% end %>
In users_controller.rb:
  def update
    current_password = params[:user].delete(:current_password) # Return and simultaneously delete value
    respond_to do |format|
      if @user.update(user_params) && @user.authenticate(current_password)
        format.html { redirect_to users_url, notice: "User #{@user.name} was successfully updated." }
        format.json { head :no_content }
      else
        @user.errors.add(:current_password, "for user is incorrect") unless @user.authenticate(current_password)
        format.html { render action: 'edit' }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end
This will give a consistent-looking error for an incorrect current password field, appearing as if it has failed a model validation (which it of course hasn’t). If there are any validation errors from the other fields they will also appear at the same time. The below solutions only seem to operate on the currently logged in user, which could either be a good thing or a bad thing, but I feel like my solution is slightly cleaner and what the book (at least the current edition) was asking for.

malevsilich

in users/_form.html.erb:

  <fieldset>
    <legend>Enter user details</legend>
    <div>
      <%= f.label :name %><br />
      <%= f.text_field :name, size: 40 %>
    </div>
    <% if params[:action]=="edit" || params[:action]=="update" %>
      <div>
        <%= f.label :current_password, :class => "long_label" %><br />
        <%= f.password_field :current_password, size: 40 %>
      </div>
    <% end %>
    <div>
      <%= f.label :password %><br />
      <%= f.password_field :password, size: 40 %>
    </div>
    <div>
      <%= f.label :password_confirmation, 'Confirm' %>
      <%= f.password_field :password_confirmation, size: 40 %>
    </div>

    <div>
      <%= f.submit %>
    </div>

  </fieldset>

in users_controller.rb:

  def update
    @user = User.find(params[:id])
    cp = params[:user].delete('current_password')
    @user.errors.add(:current_password, 'is not correct') unless @user.authenticate(cp)

    respond_to do |format|
      if @user.errors.empty? and @user.update_attributes(params[:user])
        format.html { redirect_to users_url, notice: "User #{@user.name} was successfully updated." }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

in user.rb:

    validates :password, presence: true

somebody

I did something different:

In the users_controllers.rb

def edit
  @user = User.find(params[:id])
  params[:action] = :edit
end
def update
  @user = User.find(params[:id])    
  if @user.authenticate(params:user)    
    params[:user].delete :current_password      
    respond_to do |format|      
      if @user.update_attributes(params[:user])
        format.html { redirect_to users_url, notice: "User #{@user.name} was successfully updated." }
        format.json { head :ok }
      else
        format.html { render action: "edit" }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end      
  else
    redirect_to edit_user_path(@user), notice: 'Current password is incorrect'
  end      
end

in the _form.html.erb (users) I added:

<% if params[:action] == :edit %>
  
<%= f.label :current_password, 'Current password' %> <%= f.password_field :current_password, size: 40 %>
<% end %>

in the edit.html.erb (users) I added:

<% if notice %>

<%= notice %>

<% end %>

Following line doesn’t display correctly in browser:

if @user.authenticate(params:user)


Instead it should looks like this:

if @user.authenticate(params[:user][:current_password])