0

My goal is to create a profile page where the (logged in) user can choose to either update their email or their password (in separate forms so not both at the same time) without navigating away from the page.

Updating one's email is as simple as entering their new email and hitting the "Save Changes" submit button.

Updating one's password requires the user to enter their old password, their new password, and a confirmation of their new password then hitting the "Update Password" button. The problem must be in the update_pwd method.

users_controller.rb

# ...

def edit # template: edit.html.erb
    @user = User.find(current_user)
end

def update_email
    @user = User.find(current_user)
    if params[:commit] == 'Save Changes'
        if @user.update_attributes(user_params_email)
            redirect_to me_url
            flash[:notice] = "Your changes have been saved"
        else # either invalid or taken
            render :edit
        end
   else 
        render :edit
   end
end

def update_pwd
    @user = User.find(current_user)
    if params[:commit] == 'Update Password' 
        if @user.update_attributes(user_params_pwd) && User.find_by(username: current_user.username).try(:authenticate, params[:current_password])
            redirect_to me_url
            flash[:notice] = "Password updated!"
        else
            flash.now[:alert] = @user.errors.full_messages[0]
            render :edit
        end
    else
        render :edit
    end
end

private

#def user_params
    #params.require(:user).permit(:id, :username, :email, :password, :password_confirmation)
#end

def user_params_email
    params.require(:user).permit(:email)
end

def user_params_pwd
    params.require(:user).permit(:password, :password_confirmation, :current_password)
end

edit.html.erb

<%= form_for(current_user, :url => {:controller => 'users', :action => 'update_email'}) do |f| %>

    <% if @user.errors.any? %>
        <% for message in @user.errors.full_messages %>
            <li><%= message %></li>
        <% end %>
    <% end %>

    <p> Current Email: <%= current_user.email %> </p>
    <p> New Email: <%= f.text_field :email %> </p>

   <%= f.submit "Save Changes" %>

<% end %>

<%= form_for(current_user, :url => {:controller => 'users', :action => 'update_pwd'}) do |g| %>

    <p>Old Password<br>
    <%= password_field_tag :current_password, params[:password] %></p>
    <p>New Password<br>
    <%= g.password_field :password %></p>
    <p>Confirm New Password<br>
    <%= g.password_field :password_confirmation %></p>

    <%= g.submit "Update Password" %>
<% end %>

routes.rb

# ...
get '/me' => 'users#edit'
patch '/me' => 'users#update_email'
patch '/me' => 'users#update_pwd'
# ...

Now, I've been able to get the email updating to work as desired (with the necessary error messages/validations and so forth) but whenever the update password button is clicked, the view is rendered but nothing happens. Instead, it seems as if the update_email function is being called:

Started PATCH "/me" for ::1 at 2015-05-20 10:34:31 -0500
Processing by UsersController#update_email as HTML
Parameters: {"utf8"=>"V", "authenticity_token"=>"msEsj6yxfdrbXjjdm6cH3JamrFU8R1EoZ5asmE831GSxLwpiiIW/wmGrr9HiQxFDySJtW5MKK6Ezq9hZaMNFtA==", "current_password"=>"[FILTERED]", "user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Update Password"}
←[1m←[36mUser Load (0.0ms)←[0m  ←[1mSELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1←[0m  [["id", 2]]
DEPRECATION WARNING: You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`. (called from update_email ...)

user.rb

# ...

has_secure_password

validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }   
validates_uniqueness_of :email

validates :password, length:{ minimum: 8 }, on: :create
validates :password_confirmation, presence: true, on: :create
# ...

application_controller.rb

# ...
helper_method :current_user

private

def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
    rescue ActiveRecord::RecordNotFound
end

Error log (as seen above)

Started PATCH "/me" for ::1 at 2015-05-20 10:34:31 -0500
Processing by UsersController#update_email as HTML
Parameters: {"utf8"=>"V", "authenticity_token"=>"msEsj6yxfdrbXjjdm6cH3JamrFU8R1EoZ5asmE831GSxLwpiiIW/wmGrr9HiQxFDySJtW5MKK6Ezq9hZaMNFtA==", "current_password"=>"[FILTERED]", "user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Update Password"}
←[1m←[36mUser Load (0.0ms)←[0m  ←[1mSELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1←[0m  [["id", 2]]
DEPRECATION WARNING: You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`. (called from update_email ...)
michael
  • 167
  • 5
  • 23
  • please post your update password action log – Amit Sharma May 20 '15 at 18:50
  • @AmitSharma The log posted under the routes heading is for the update_pwd action - triggered after clicking on the "Update Password" btn. As you can see, for some odd reason update_email is being called instead. – michael May 20 '15 at 18:57
  • Please post your log _to the question_ and go through and use full, correct English -- no acronyms, no btn for button. Also, it's generally frowned upon to put tags in the title when you already have tags in the tags. – Nic May 20 '15 at 20:48
  • Slight type as well, I think: You have `` in several places instead of `
    `.
    – Nic May 20 '15 at 20:50
  • @QPaysTaxes Sorry, I can't say I get what you mean by log to the question; the edits I made only involved spelling, and now changing instances of to
    . Thanks.
    – michael May 20 '15 at 21:03
  • I mean that you need to add the log, which you seem to already have, into your question, using the [edit](http://stackoverflow.com/posts/30353715/edit) link. – Nic May 20 '15 at 21:12
  • your both actions has same path in routes `/me`, I think the problem is occuring becase of that. – Amit Sharma May 21 '15 at 07:15
  • @AmitSharma That makes sense, but then how should I define my routes so that I am able to achieve what I'm trying to do? – michael May 21 '15 at 14:34
  • @marem, I have added the answer please try the code and revert back if you face any issue. – Amit Sharma May 21 '15 at 15:36

1 Answers1

0

You can try the following, I think this will help. Please revert back if you face any issue.

routes.rb

get '/me' => 'users#edit'
patch '/me' => 'users#update_data'

edit.html.erb

<%= form_for(current_user, :url => {:controller => 'users', :action => 'update_data'}) do |f| %>

    <% if @user.errors.any? %>
        <% for message in @user.errors.full_messages %>
            <li><%= message %></li>
        <% end %>
    <% end %>

    <p> Current Email: <%= current_user.email %> </p>
    <p> New Email: <%= f.text_field :email %> </p>

   <%= f.submit 'Save Changes', name: 'update_email' %>

<% end %>

<%= form_for(current_user, :url => {:controller => 'users', :action => 'update_data'}) do |g| %>

    <p>Old Password<br>
    <%= password_field_tag :current_password, params[:password] %></p>
    <p>New Password<br>
    <%= g.password_field :password %></p>
    <p>Confirm New Password<br>
    <%= g.password_field :password_confirmation %></p>

    <%= g.submit 'Update Password', name: 'update_password' %>
<% end %>

users_controller.rb

def edit
    @user = User.find(current_user)
end

def update_data
  @user = User.find(current_user)
  if params[:commit] == "update_email"
    if @user.update_attributes(user_params_email)
      flash[:notice] = "Your changes have been saved"
      redirect_to me_url
    else
      render :edit
    end
  elsif params[:commit] == "update_password"
    if @user.update_attributes(user_params_pwd) && User.find_by(username: current_user.username).try(:authenticate, params[:current_password])
      flash[:notice] = "Password updated!"
      redirect_to me_url
    else
      flash.now[:alert] = @user.errors.full_messages[0]
      render :edit
    end
  else 
    render :edit
  end
end

private

def user_params_email
  params.require(:user).permit(:email)
end

def user_params_pwd
  params.require(:user).permit(:password, :password_confirmation, :current_password)
end
Amit Sharma
  • 3,427
  • 2
  • 15
  • 20