Iros: Change the views/users/edit.html.erb content to


<h1>Editing user</h1>

<% form_for(@user) do |f| %>
  <%= f.error_messages %>

    <p>
        <label for="user_name">Name: </label>
        <%= f.text_field :name, :size =>40 %>
    </p>

    <p>
        <label for="user_password">Password: </label>
        <%= f.password_field :password, :size =>40 %>
    </p>

    <p>
        <label for="user_password_confirmation">Confirm: </label>
        <%= f.password_field :password_confirmation, :size =>40 %>
    </p>

  <p>
    <%= f.submit "Update" %>
  </p>
<% end %>

<%= link_to 'Show', @user %> |
<%= link_to 'Back', users_path %>

gackd:

The method posted by Iros is what I first did. It’s the obvious easy solution. What I’m wondering is: how do you do this in a way that the user has to enter their current password to change their password?

I tried adding a field to edit.html.erb the way shown above but Rails always complained about it. I sort of got it to work with fields_for like this:

<% fields_for :current_password do |f| %>
<%= f.password_field :current_password %>
<% end %>

That ended up in the params has as params:current_password.

That sucks.

I decided to see if I could use User#authenticate with @user.name and that params[][] mess to see if the user’s current password was correct and then update to the new password provided. It was ugly but seemed to work okay.

Any suggestions?

Jinyoung:

To gackd. You can use password_field_tag function.


<p>
  <%= label_tag 'Current password' %>:
  <%= password_field_tag :current_password, '', :size => 40 %>
</p>

I suggest below additional code to Iros’s one.

In user.rb

class User < ActiveRecord::Base
  # ...

  validates_presence_of :name, :password

  # ...
h4. MarkG Since you already know the name of the user you’re attempting to edit, it’d be smarter to pre-populate that field…chances are that if you’re editing their account it’s because of a password change, not that they’ve legally changed their name [sure it can happen, but it’s not the most common situation :-) ]

# ...
<p>
  <label for="user_name">Name: </label>
  <%= f.text_field :name, :size =>40, :value => @user.name %>
</p>
# ...

Grazybom:

Iros’s solution does not work for me, it changes only view layout but nothing happens on the server side. It does not update the hashed_password. Here is my solution. First, I added a new method to the user’s model:

  def self.update_user(params,salt)
    # params: {name, confirmation_password}
    user = {}
    unless params[:password_confirmation].blank?
      hashed_confirmation_password = User.encrypted_password(params[:password_confirmation],salt) 
      user[:name] = params[:name]
      user[:hashed_password] = hashed_confirmation_password
      user[:salt] = salt
    end
    return user
  end  

and, second, I changed the update method in users_controller.rb:


  def update
    @user = User.find(params[:id])
    user = User.update_user(params[:user],@user[:salt])
    return redirect_to(:action =>:index) if user.blank?

    respond_to do |format|
      if @user.update_attributes(user)
..............................

Now, it saves an updated password if the field was changed.

But, there is always “but”, I cannot find the way how to make validation working if I add password and password_confirmation fields. If I create a new user User.new() then validation works (name,password), but if I use User.find() it does not work..

syborg:

Let me explain my soution. Possibly there are more efficient ones but the Convention over configuration asks to memorize or have a lot of documentacion and/or experience. It’s not my case.

So, here is what I did:

First, I exactly made a new edit.html.erb as Iro’s one.

Second, I have modified a line and added another in the update method:


  def update
    @user = User.find(params[:id])

    respond_to do |format|
      if (@user.update_attributes(params[:user]) if !params[:user][:password].blank?) #modified line
        flash[:notice] = "User #{@user.name} was successfully updated." 
        format.html { redirect_to :action=>:index }
        format.xml  { head :ok }
      else
        flash[:notice] = "User #{@user.name} needs a password" # added line 
        format.html { render :action => "edit" }
        format.xml  { render :xml => @user.errors, :status => :unprocessable_entity }
      end
    end
  end

I suppose it is not the niciest code, more than that, I’m sure there is some better way to do that. But works

BTW, does anybody know why “validate :password_non_blank” in user model doesn’t work here as it did for the ‘new’ action?