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 ...)
`. – Nic May 20 '15 at 20:50
. Thanks. – michael May 20 '15 at 21:03