Browse Source

Validate that password match when updating and show errors if they don't (#158)

* Validate that password match and show error if not

* User spec

* Test user update failure

* Format error messages for Form builder gem

* Test error message
pull/160/head
baarkerlounger 3 years ago committed by GitHub
parent
commit
3b7bc3f2bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      app/controllers/users_controller.rb
  2. 2
      app/views/users/edit.html.erb
  3. 14
      app/views/users/edit_password.html.erb
  4. 2
      app/views/users/reset_password.html.erb
  5. 2
      spec/features/user_spec.rb
  6. 49
      spec/requests/user_controller_spec.rb

20
app/controllers/users_controller.rb

@ -10,6 +10,12 @@ class UsersController < ApplicationController
bypass_sign_in @user bypass_sign_in @user
flash[:notice] = I18n.t("devise.passwords.updated") if user_params.key?("password") flash[:notice] = I18n.t("devise.passwords.updated") if user_params.key?("password")
redirect_to user_path(@user) redirect_to user_path(@user)
elsif user_params.key?("password")
format_error_messages
render :edit_password, status: :unprocessable_entity
else
format_error_messages
render :edit, status: :unprocessable_entity
end end
end end
@ -39,6 +45,18 @@ class UsersController < ApplicationController
private private
def format_error_messages
errors = @user.errors.to_hash
@user.errors.clear
errors.each do |attribute, message|
@user.errors.add attribute.to_sym, format_error_message(attribute, message)
end
end
def format_error_message(attribute, message)
[attribute.to_s.humanize.capitalize, message].join(" ")
end
def password_params def password_params
{ password: SecureRandom.hex(8) } { password: SecureRandom.hex(8) }
end end
@ -48,7 +66,7 @@ private
end end
def user_params def user_params
params.require(:user).permit(:email, :name, :password, :role) params.require(:user).permit(:email, :name, :password, :password_confirmation, :role)
end end
def find_resource def find_resource

2
app/views/users/edit.html.erb

@ -10,6 +10,8 @@
<%= form_for(current_user, as: :user, html: { method: :patch }) do |f| %> <%= form_for(current_user, as: :user, html: { method: :patch }) do |f| %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds"> <div class="govuk-grid-column-two-thirds">
<%= f.govuk_error_summary %>
<h1 class="govuk-heading-l"> <h1 class="govuk-heading-l">
<%= content_for(:title) %> <%= content_for(:title) %>
</h1> </h1>

14
app/views/users/edit_password.html.erb

@ -7,23 +7,25 @@
) %> ) %>
<% end %> <% end %>
<%= form_for(current_user, as: :user, html: { method: :patch }) do |f| %> <%= form_for(@user, as: :user, html: { method: :patch }) do |f| %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds"> <div class="govuk-grid-column-two-thirds">
<%= f.govuk_error_summary %>
<h1 class="govuk-heading-l"> <h1 class="govuk-heading-l">
<%= content_for(:title) %> <%= content_for(:title) %>
</h1> </h1>
<%= f.govuk_password_field :current_password,
label: { text: "Current password" },
autocomplete: "current-password"
%>
<%= f.govuk_password_field :password, <%= f.govuk_password_field :password,
label: { text: "New password" },
hint: @minimum_password_length ? { text: "Your password must be at least #{@minimum_password_length} characters and hard to guess." } : nil, hint: @minimum_password_length ? { text: "Your password must be at least #{@minimum_password_length} characters and hard to guess." } : nil,
autocomplete: "new-password" autocomplete: "new-password"
%> %>
<%= f.govuk_password_field :password_confirmation,
label: { text: "Confirm new password" }
%>
<%= f.govuk_submit "Update" %> <%= f.govuk_submit "Update" %>
</div> </div>
</div> </div>

2
app/views/users/reset_password.html.erb

@ -11,6 +11,8 @@
<%= f.hidden_field :reset_password_token %> <%= f.hidden_field :reset_password_token %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds"> <div class="govuk-grid-column-two-thirds">
<%= f.govuk_error_summary %>
<h1 class="govuk-heading-l"> <h1 class="govuk-heading-l">
<%= content_for(:title) %> <%= content_for(:title) %>
</h1> </h1>

2
spec/features/user_spec.rb

@ -146,8 +146,8 @@ RSpec.describe "User Features" do
visit("/users/#{user.id}") visit("/users/#{user.id}")
find('[data-qa="change-password"]').click find('[data-qa="change-password"]').click
expect(page).to have_content("Change your password") expect(page).to have_content("Change your password")
fill_in("user[current_password]", with: "pAssword1")
fill_in("user[password]", with: "Password123!") fill_in("user[password]", with: "Password123!")
fill_in("user[password_confirmation]", with: "Password123!")
click_button("Update") click_button("Update")
expect(page).to have_current_path("/users/#{user.id}") expect(page).to have_current_path("/users/#{user.id}")
end end

49
spec/requests/user_controller_spec.rb

@ -44,6 +44,25 @@ RSpec.describe UsersController, type: :request do
get "/users/password/edit?reset_password_token=#{enc}" get "/users/password/edit?reset_password_token=#{enc}"
expect(page).to have_css("h1", class: "govuk-heading-l", text: "Reset your password") expect(page).to have_css("h1", class: "govuk-heading-l", text: "Reset your password")
end end
context "update password" do
let(:params) do
{
id: user.id, user: { password: new_value, password_confirmation: "something_else" }
}
end
before do
sign_in user
put "/users/#{user.id}", headers: headers, params: params
end
it "shows an error if passwords don't match" do
expect(response).to have_http_status(:unprocessable_entity)
expect(page).to have_selector("#error-summary-title")
expect(page).to have_content("Password confirmation doesn't match Password")
end
end
end end
end end
@ -132,6 +151,18 @@ RSpec.describe UsersController, type: :request do
end end
end end
context "update fails to persist" do
before do
allow_any_instance_of(User).to receive(:update).and_return(false)
sign_in user
patch "/users/#{user.id}", headers: headers, params: params
end
it "show an error" do
expect(response).to have_http_status(:unprocessable_entity)
end
end
context "current user is another user" do context "current user is another user" do
let(:params) { { id: unauthorised_user.id, user: { name: new_value } } } let(:params) { { id: unauthorised_user.id, user: { name: new_value } } }
@ -144,5 +175,23 @@ RSpec.describe UsersController, type: :request do
expect(response).to have_http_status(:not_found) expect(response).to have_http_status(:not_found)
end end
end end
context "update password" do
let(:params) do
{
id: user.id, user: { password: new_value, password_confirmation: "something_else" }
}
end
before do
sign_in user
patch "/users/#{user.id}", headers: headers, params: params
end
it "shows an error if passwords don't match" do
expect(response).to have_http_status(:unprocessable_entity)
expect(page).to have_selector("#error-summary-title")
end
end
end end
end end

Loading…
Cancel
Save