| @@ -25,7 +25,7 @@ gem 'jbuilder', '~> 2.5' | |||||
| # Use Redis adapter to run Action Cable in production | # Use Redis adapter to run Action Cable in production | ||||
| # gem 'redis', '~> 3.0' | # gem 'redis', '~> 3.0' | ||||
| # Use ActiveModel has_secure_password | # Use ActiveModel has_secure_password | ||||
| # gem 'bcrypt', '~> 3.1.7' | |||||
| gem 'bcrypt', '~> 3.1.7' | |||||
| # Use Capistrano for deployment | # Use Capistrano for deployment | ||||
| # gem 'capistrano-rails', group: :development | # gem 'capistrano-rails', group: :development | ||||
| @@ -39,6 +39,7 @@ GEM | |||||
| minitest (~> 5.1) | minitest (~> 5.1) | ||||
| tzinfo (~> 1.1) | tzinfo (~> 1.1) | ||||
| arel (7.1.4) | arel (7.1.4) | ||||
| bcrypt (3.1.11) | |||||
| builder (3.2.2) | builder (3.2.2) | ||||
| byebug (9.0.6) | byebug (9.0.6) | ||||
| coffee-rails (4.2.1) | coffee-rails (4.2.1) | ||||
| @@ -154,6 +155,7 @@ PLATFORMS | |||||
| ruby | ruby | ||||
| DEPENDENCIES | DEPENDENCIES | ||||
| bcrypt (~> 3.1.7) | |||||
| byebug | byebug | ||||
| coffee-rails (~> 4.2) | coffee-rails (~> 4.2) | ||||
| jbuilder (~> 2.5) | jbuilder (~> 2.5) | ||||
| @@ -0,0 +1,3 @@ | |||||
| # Place all the behaviors and hooks related to the matching controller here. | |||||
| # All this logic will automatically be available in application.js. | |||||
| # You can use CoffeeScript in this file: http://coffeescript.org/ | |||||
| @@ -0,0 +1,3 @@ | |||||
| # Place all the behaviors and hooks related to the matching controller here. | |||||
| # All this logic will automatically be available in application.js. | |||||
| # You can use CoffeeScript in this file: http://coffeescript.org/ | |||||
| @@ -0,0 +1,3 @@ | |||||
| # Place all the behaviors and hooks related to the matching controller here. | |||||
| # All this logic will automatically be available in application.js. | |||||
| # You can use CoffeeScript in this file: http://coffeescript.org/ | |||||
| @@ -0,0 +1,3 @@ | |||||
| // Place all the styles related to the Admin controller here. | |||||
| // They will automatically be included in application.css. | |||||
| // You can use Sass (SCSS) here: http://sass-lang.com/ | |||||
| @@ -0,0 +1,89 @@ | |||||
| body { | |||||
| background-color: #fff; | |||||
| color: #333; | |||||
| font-family: verdana, arial, helvetica, sans-serif; | |||||
| font-size: 13px; | |||||
| line-height: 18px; | |||||
| margin: 33px; | |||||
| } | |||||
| p, ol, ul, td { | |||||
| font-family: verdana, arial, helvetica, sans-serif; | |||||
| font-size: 13px; | |||||
| line-height: 18px; | |||||
| margin: 33px; | |||||
| } | |||||
| pre { | |||||
| background-color: #eee; | |||||
| padding: 10px; | |||||
| font-size: 11px; | |||||
| } | |||||
| a { | |||||
| color: #000; | |||||
| &:visited { | |||||
| color: #666; | |||||
| } | |||||
| &:hover { | |||||
| color: #fff; | |||||
| background-color: #000; | |||||
| } | |||||
| } | |||||
| th { | |||||
| padding-bottom: 5px; | |||||
| } | |||||
| td { | |||||
| padding-bottom: 7px; | |||||
| padding-left: 5px; | |||||
| padding-right: 5px; | |||||
| } | |||||
| div { | |||||
| &.field, &.actions { | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| } | |||||
| #notice { | |||||
| color: green; | |||||
| } | |||||
| .field_with_errors { | |||||
| padding: 2px; | |||||
| background-color: red; | |||||
| display: table; | |||||
| } | |||||
| #error_explanation { | |||||
| width: 450px; | |||||
| border: 2px solid red; | |||||
| padding: 7px; | |||||
| padding-bottom: 0; | |||||
| margin-bottom: 20px; | |||||
| background-color: #f0f0f0; | |||||
| h2 { | |||||
| text-align: left; | |||||
| font-weight: bold; | |||||
| padding: 5px 5px 5px 15px; | |||||
| font-size: 12px; | |||||
| margin: -7px; | |||||
| margin-bottom: 0; | |||||
| background-color: #c00; | |||||
| color: #fff; | |||||
| } | |||||
| ul li { | |||||
| font-size: 12px; | |||||
| list-style: square; | |||||
| } | |||||
| } | |||||
| label { | |||||
| display: block; | |||||
| } | |||||
| @@ -0,0 +1,3 @@ | |||||
| // Place all the styles related to the Sessions controller here. | |||||
| // They will automatically be included in application.css. | |||||
| // You can use Sass (SCSS) here: http://sass-lang.com/ | |||||
| @@ -0,0 +1,3 @@ | |||||
| // Place all the styles related to the Users controller here. | |||||
| // They will automatically be included in application.css. | |||||
| // You can use Sass (SCSS) here: http://sass-lang.com/ | |||||
| @@ -0,0 +1,4 @@ | |||||
| class AdminController < ApplicationController | |||||
| def index | |||||
| end | |||||
| end | |||||
| @@ -1,3 +1,12 @@ | |||||
| class ApplicationController < ActionController::Base | class ApplicationController < ActionController::Base | ||||
| protect_from_forgery with: :exception | protect_from_forgery with: :exception | ||||
| before_action :authorize | |||||
| protected | |||||
| def authorize | |||||
| unless User.find_by(id: session[:user_id]) | |||||
| redirect_to login_url | |||||
| end | |||||
| end | |||||
| end | end | ||||
| @@ -0,0 +1,20 @@ | |||||
| class SessionsController < ApplicationController | |||||
| skip_before_action :authorize | |||||
| def new | |||||
| end | |||||
| def create | |||||
| user = User.find_by(name: params[:name]) | |||||
| if user&.authenticate(params[:password]) | |||||
| session[:user_id] = user.id | |||||
| redirect_to admin_url | |||||
| else | |||||
| redirect_to login_url | |||||
| end | |||||
| end | |||||
| def destroy | |||||
| session[:user_id] = nil | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,74 @@ | |||||
| class UsersController < ApplicationController | |||||
| before_action :set_user, only: [:show, :edit, :update, :destroy] | |||||
| # GET /users | |||||
| # GET /users.json | |||||
| def index | |||||
| @users = User.order(:name) | |||||
| end | |||||
| # GET /users/1 | |||||
| # GET /users/1.json | |||||
| def show | |||||
| end | |||||
| # GET /users/new | |||||
| def new | |||||
| @user = User.new | |||||
| end | |||||
| # GET /users/1/edit | |||||
| def edit | |||||
| end | |||||
| # POST /users | |||||
| # POST /users.json | |||||
| def create | |||||
| @user = User.new(user_params) | |||||
| respond_to do |format| | |||||
| if @user.save | |||||
| format.html { redirect_to @user, notice: 'User was successfully created.' } | |||||
| format.json { render :show, status: :created, location: @user } | |||||
| else | |||||
| format.html { render :new } | |||||
| format.json { render json: @user.errors, status: :unprocessable_entity } | |||||
| end | |||||
| end | |||||
| end | |||||
| # PATCH/PUT /users/1 | |||||
| # PATCH/PUT /users/1.json | |||||
| def update | |||||
| respond_to do |format| | |||||
| if @user.update(user_params) | |||||
| format.html { redirect_to @user, notice: 'User was successfully updated.' } | |||||
| format.json { render :show, status: :ok, location: @user } | |||||
| else | |||||
| format.html { render :edit } | |||||
| format.json { render json: @user.errors, status: :unprocessable_entity } | |||||
| end | |||||
| end | |||||
| end | |||||
| # DELETE /users/1 | |||||
| # DELETE /users/1.json | |||||
| def destroy | |||||
| @user.destroy | |||||
| respond_to do |format| | |||||
| format.html { redirect_to users_url, notice: 'User was successfully destroyed.' } | |||||
| format.json { head :no_content } | |||||
| end | |||||
| end | |||||
| private | |||||
| # Use callbacks to share common setup or constraints between actions. | |||||
| def set_user | |||||
| @user = User.find(params[:id]) | |||||
| end | |||||
| # Never trust parameters from the scary internet, only allow the white list through. | |||||
| def user_params | |||||
| params.require(:user).permit(:name, :password, :password_confirmation) | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,2 @@ | |||||
| module AdminHelper | |||||
| end | |||||
| @@ -0,0 +1,2 @@ | |||||
| module SessionsHelper | |||||
| end | |||||
| @@ -0,0 +1,2 @@ | |||||
| module UsersHelper | |||||
| end | |||||
| @@ -0,0 +1,3 @@ | |||||
| class User < ApplicationRecord | |||||
| has_secure_password | |||||
| end | |||||
| @@ -0,0 +1,2 @@ | |||||
| <h1>Admin#index</h1> | |||||
| <p>Find me in app/views/admin/index.html.erb</p> | |||||
| @@ -0,0 +1,2 @@ | |||||
| <h1>Sessions#create</h1> | |||||
| <p>Find me in app/views/sessions/create.html.erb</p> | |||||
| @@ -0,0 +1,2 @@ | |||||
| <h1>Sessions#destroy</h1> | |||||
| <p>Find me in app/views/sessions/destroy.html.erb</p> | |||||
| @@ -0,0 +1,15 @@ | |||||
| <%= form_tag do %> | |||||
| <div class="field"> | |||||
| <%= label_tag :name %> | |||||
| <%= text_field_tag :name %> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <%= label_tag :password %> | |||||
| <%= password_field_tag :password %> | |||||
| </div> | |||||
| <div class="actions"> | |||||
| <%= submit_tag 'Login' %> | |||||
| </div> | |||||
| <% end %> | |||||
| @@ -0,0 +1,32 @@ | |||||
| <%= form_for(user) do |f| %> | |||||
| <% if user.errors.any? %> | |||||
| <div id="error_explanation"> | |||||
| <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2> | |||||
| <ul> | |||||
| <% user.errors.full_messages.each do |message| %> | |||||
| <li><%= message %></li> | |||||
| <% end %> | |||||
| </ul> | |||||
| </div> | |||||
| <% end %> | |||||
| <div class="field"> | |||||
| <%= f.label :name %> | |||||
| <%= f.text_field :name %> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <%= f.label :password %> | |||||
| <%= f.password_field :password %> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <%= f.label :password_confirmation %> | |||||
| <%= f.password_field :password_confirmation %> | |||||
| </div> | |||||
| <div class="actions"> | |||||
| <%= f.submit %> | |||||
| </div> | |||||
| <% end %> | |||||
| @@ -0,0 +1,2 @@ | |||||
| json.extract! user, :id, :name, :created_at, :updated_at | |||||
| json.url user_url(user, format: :json) | |||||
| @@ -0,0 +1,6 @@ | |||||
| <h1>Editing User</h1> | |||||
| <%= render 'form', user: @user %> | |||||
| <%= link_to 'Show', @user %> | | |||||
| <%= link_to 'Back', users_path %> | |||||
| @@ -0,0 +1,27 @@ | |||||
| <p id="notice"><%= notice %></p> | |||||
| <h1>Users</h1> | |||||
| <table> | |||||
| <thead> | |||||
| <tr> | |||||
| <th>Name</th> | |||||
| <th colspan="3"></th> | |||||
| </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <% @users.each do |user| %> | |||||
| <tr> | |||||
| <td><%= user.name %></td> | |||||
| <td><%= link_to 'Show', user %></td> | |||||
| <td><%= link_to 'Edit', edit_user_path(user) %></td> | |||||
| <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td> | |||||
| </tr> | |||||
| <% end %> | |||||
| </tbody> | |||||
| </table> | |||||
| <br> | |||||
| <%= link_to 'New User', new_user_path %> | |||||
| @@ -0,0 +1 @@ | |||||
| json.array! @users, partial: 'users/user', as: :user | |||||
| @@ -0,0 +1,5 @@ | |||||
| <h1>New User</h1> | |||||
| <%= render 'form', user: @user %> | |||||
| <%= link_to 'Back', users_path %> | |||||
| @@ -0,0 +1,9 @@ | |||||
| <p id="notice"><%= notice %></p> | |||||
| <p> | |||||
| <strong>Name:</strong> | |||||
| <%= @user.name %> | |||||
| </p> | |||||
| <%= link_to 'Edit', edit_user_path(@user) %> | | |||||
| <%= link_to 'Back', users_path %> | |||||
| @@ -0,0 +1 @@ | |||||
| json.partial! "users/user", user: @user | |||||
| @@ -1,3 +1,14 @@ | |||||
| Rails.application.routes.draw do | Rails.application.routes.draw do | ||||
| root 'users#index', as: 'users_index' | |||||
| get 'admin/index' | |||||
| controller :sessions do | |||||
| get 'login' => :new | |||||
| post 'login' => :create | |||||
| delete 'logout' => :destroy | |||||
| end | |||||
| resources :users | |||||
| # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html | ||||
| end | end | ||||
| @@ -0,0 +1,10 @@ | |||||
| class CreateUsers < ActiveRecord::Migration[5.0] | |||||
| def change | |||||
| create_table :users do |t| | |||||
| t.string :name | |||||
| t.string :password_digest | |||||
| t.timestamps | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,22 @@ | |||||
| # This file is auto-generated from the current state of the database. Instead | |||||
| # of editing this file, please use the migrations feature of Active Record to | |||||
| # incrementally modify your database, and then regenerate this schema definition. | |||||
| # | |||||
| # Note that this schema.rb definition is the authoritative source for your | |||||
| # database schema. If you need to create the application database on another | |||||
| # system, you should be using db:schema:load, not running all the migrations | |||||
| # from scratch. The latter is a flawed and unsustainable approach (the more migrations | |||||
| # you'll amass, the slower it'll run and the greater likelihood for issues). | |||||
| # | |||||
| # It's strongly recommended that you check this file into your version control system. | |||||
| ActiveRecord::Schema.define(version: 20161124123704) do | |||||
| create_table "users", force: :cascade do |t| | |||||
| t.string "name" | |||||
| t.string "password_digest" | |||||
| t.datetime "created_at", null: false | |||||
| t.datetime "updated_at", null: false | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,9 @@ | |||||
| require 'test_helper' | |||||
| class AdminControllerTest < ActionDispatch::IntegrationTest | |||||
| test "should get index" do | |||||
| get admin_index_url | |||||
| assert_response :success | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,19 @@ | |||||
| require 'test_helper' | |||||
| class SessionsControllerTest < ActionDispatch::IntegrationTest | |||||
| test "should get new" do | |||||
| get sessions_new_url | |||||
| assert_response :success | |||||
| end | |||||
| test "should get create" do | |||||
| get sessions_create_url | |||||
| assert_response :success | |||||
| end | |||||
| test "should get destroy" do | |||||
| get sessions_destroy_url | |||||
| assert_response :success | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,48 @@ | |||||
| require 'test_helper' | |||||
| class UsersControllerTest < ActionDispatch::IntegrationTest | |||||
| setup do | |||||
| @user = users(:one) | |||||
| end | |||||
| test "should get index" do | |||||
| get users_url | |||||
| assert_response :success | |||||
| end | |||||
| test "should get new" do | |||||
| get new_user_url | |||||
| assert_response :success | |||||
| end | |||||
| test "should create user" do | |||||
| assert_difference('User.count') do | |||||
| post users_url, params: { user: { name: @user.name, password: 'secret', password_confirmation: 'secret' } } | |||||
| end | |||||
| assert_redirected_to user_url(User.last) | |||||
| end | |||||
| test "should show user" do | |||||
| get user_url(@user) | |||||
| assert_response :success | |||||
| end | |||||
| test "should get edit" do | |||||
| get edit_user_url(@user) | |||||
| assert_response :success | |||||
| end | |||||
| test "should update user" do | |||||
| patch user_url(@user), params: { user: { name: @user.name, password: 'secret', password_confirmation: 'secret' } } | |||||
| assert_redirected_to user_url(@user) | |||||
| end | |||||
| test "should destroy user" do | |||||
| assert_difference('User.count', -1) do | |||||
| delete user_url(@user) | |||||
| end | |||||
| assert_redirected_to users_url | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,9 @@ | |||||
| # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html | |||||
| one: | |||||
| name: MyString | |||||
| password_digest: <%= BCrypt::Password.create('secret') %> | |||||
| two: | |||||
| name: MyString | |||||
| password_digest: <%= BCrypt::Password.create('secret') %> | |||||
| @@ -0,0 +1,7 @@ | |||||
| require 'test_helper' | |||||
| class UserTest < ActiveSupport::TestCase | |||||
| # test "the truth" do | |||||
| # assert true | |||||
| # end | |||||
| end | |||||