Browse Source

Add edit action to Users controller

Frans Bergman 7 years ago
parent
commit
2093440063

+ 2 - 0
Gemfile

@@ -31,6 +31,8 @@ gem 'jbuilder', '~> 2.5'
 gem 'jquery-rails', '~> 4.3.1'
 # FontAwesome
 gem "font-awesome-rails"
+# Bootstrap Forms
+gem 'bootstrap_form', '~> 2.7.0'
 # Use Redis adapter to run Action Cable in production
 # gem 'redis', '~> 3.0'
 # Use ActiveModel has_secure_password

+ 2 - 0
Gemfile.lock

@@ -48,6 +48,7 @@ GEM
     bootstrap-sass (3.3.7)
       autoprefixer-rails (>= 5.2.1)
       sass (>= 3.3.4)
+    bootstrap_form (2.7.0)
     builder (3.2.3)
     byebug (9.1.0)
     capybara (2.16.1)
@@ -195,6 +196,7 @@ PLATFORMS
 DEPENDENCIES
   bcrypt (~> 3.1.7)
   bootstrap-sass (~> 3.3.7)
+  bootstrap_form (~> 2.7.0)
   byebug
   capybara (~> 2.13)
   coffee-rails (~> 4.2)

+ 1 - 0
app/assets/stylesheets/application.css

@@ -10,6 +10,7 @@
  * files in this directory. Styles in this file should be added after the last require_* statement.
  * It is generally better to create a new file per style scope.
  *
+ *= require rails_bootstrap_forms
  *= require_tree .
  *= require_self
  */

+ 34 - 1
app/controllers/users_controller.rb

@@ -1,9 +1,42 @@
 class UsersController < ApplicationController
 
+  before_action :set_user, only: [:show, :edit, :update, :destroy]
+  before_action :correct_user, only: [:edit, :update]
+
   def show
-    @user = User.find(params[:id])
   end
 
   def new
   end
+
+  def edit
+  end
+
+  def update
+    if @user.update(user_params)
+      flash[:success] = 'Profile updated'
+      redirect_to @user
+    else
+      render :edit
+    end
+  end
+
+  private
+    # Use callbacks to share common setup or constraints between actions.
+    def set_user
+      @user = User.find(params[:id])
+    end
+
+    # Only allow certain attributes to be updated over the web.
+    def user_params
+      params.require(:user).permit(:login, :email, :password,
+                                   :password_confirmation,
+                                   :gender, :phone)
+    end
+
+    # Confirms the correct user.
+    def correct_user
+      @user = User.find(params[:id])
+      redirect_to(root_url) unless current_user?(@user)
+    end
 end

+ 3 - 1
app/models/user.rb

@@ -14,7 +14,9 @@ class User < ApplicationRecord
                     uniqueness: { case_sensitive: false }
 
   has_secure_password
-  validates :password, presence: true, length: { minimum: 6 }
+  validates :password, presence: true, length: { minimum: 6 },
+                       if: lambda { new_record? || !password.blank? ||
+                                    !password_confirmation.blank? }
 
   enum gender: [ :unspecified, :male, :female, :other ]
 

+ 1 - 1
app/views/layouts/_navigation.html.erb

@@ -19,7 +19,7 @@
                   <%= link_to fa_icon("user fw", text: "User Profile"), current_user %>
                 </li>
                 <li>
-                  <%= link_to fa_icon("gear fw", text: "Settings"), "#" %>
+                  <%= link_to fa_icon("gear fw", text: "Settings"), edit_user_path(current_user) %>
                 </li>
                 <li class="divider"></li>
                 <li>

+ 12 - 0
app/views/shared/_error_messages.html.erb

@@ -0,0 +1,12 @@
+<% if object.errors.any? %>
+  <div id="error_explanation">
+    <div class="alert alert-danger">
+      The form contains <%= pluralize(object.errors.count, "error") %>.
+    </div>
+    <ul>
+    <% object.errors.full_messages.each do |msg| %>
+      <li><%= msg %></li>
+    <% end %>
+    </ul>
+  </div>
+<% end %>

+ 12 - 0
app/views/users/_form.html.erb

@@ -0,0 +1,12 @@
+<%= bootstrap_form_for(@user) do |f| %>
+  <%= render 'shared/error_messages', object: f.object %>
+
+  <%= f.text_field :login %>
+  <%= f.email_field :email %>
+  <%= f.phone_field :phone %>
+  <%= f.password_field :password %>
+  <%= f.password_field :password_confirmation %>
+  <%= f.select :gender, User.genders.keys, {} %>
+
+  <%= f.submit yield(:button_text), class: "btn btn-primary" %>
+<% end %>

+ 9 - 0
app/views/users/edit.html.erb

@@ -0,0 +1,9 @@
+<% provide(:title, @user.name) %>
+<% provide(:button_text, 'Save changes') %>
+
+<h1>Update profile</h1>
+<div class="row">
+  <div class="col-md-6">
+    <%= render 'form' %>
+  </div>
+</div>

+ 58 - 1
test/controllers/users_controller_test.rb

@@ -3,11 +3,68 @@ require 'test_helper'
 class UsersControllerTest < ActionDispatch::IntegrationTest
   def setup
     @user = users(:daniel)
-    log_in_as @user
+    @other_user = users(:ben)
   end
 
   test "should display age correctly" do
+    log_in_as @user
     get user_path @user
     assert_select ".user-age", /[A-z]+\: [0-9]+/
   end
+
+  test "should show user" do
+    log_in_as @user
+    get user_url(@user)
+    assert_response :success
+  end
+
+  test "should get edit" do
+    log_in_as(@user)
+    get edit_user_url(@user)
+    assert_response :success
+  end
+
+  test "should update user" do
+    log_in_as(@user)
+    patch user_url(@user), params: { user: { email: @user.email, login: @user.login } }
+    assert_redirected_to user_url(@user)
+  end
+
+  test "should redirect edit when not logged in" do
+    get edit_user_path(@user)
+    assert_not flash.empty?
+    assert_redirected_to login_url
+  end
+
+  test "should redirect update when not logged in" do
+    patch user_path(@user), params: { user: { name: @user.name,
+                                              email: @user.email } }
+    assert_not flash.empty?
+    assert_redirected_to login_url
+  end
+
+  test "should not allow the name attribute to be edited by non-admin" do
+    log_in_as(@user)
+    assert_not_equal @user.name, "Wrong Name"
+    patch user_path(@user), params: {
+                                    user: { password:              'newpass',
+                                            password_confirmation: 'newpass',
+                                            name: "Wrong Name" } }
+    assert_not_equal @user.reload.name, "Wrong Name"
+  end
+
+  test "should redirect edit when logged in as wrong user" do
+    log_in_as(@other_user)
+    get edit_user_path(@user)
+    assert flash.empty?
+    assert_redirected_to root_url
+  end
+
+  test "should redirect update when logged in as wrong user" do
+    log_in_as(@other_user)
+    patch user_path(@user), params: { user: { name: @user.name,
+                                              email: @user.email } }
+    assert flash.empty?
+    assert_redirected_to root_url
+  end
 end