Added authentication; cleaned up some UI
This commit is contained in:
parent
b3b1f1745c
commit
170098046e
1
.ruby-version
Normal file
1
.ruby-version
Normal file
@ -0,0 +1 @@
|
||||
2.3.0
|
2
Gemfile
2
Gemfile
@ -21,7 +21,7 @@ gem 'cocoon', '~> 1.2.6'
|
||||
gem 'unitwise', '~> 2.0.0'
|
||||
|
||||
# Use ActiveModel has_secure_password
|
||||
# gem 'bcrypt', '~> 3.1.7'
|
||||
gem 'bcrypt', '~> 3.1.7'
|
||||
|
||||
# Use Unicorn as the app server
|
||||
# gem 'unicorn'
|
||||
|
11
Gemfile.lock
11
Gemfile.lock
@ -37,9 +37,10 @@ GEM
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
arel (6.0.3)
|
||||
autoprefixer-rails (6.2.3)
|
||||
autoprefixer-rails (6.3.1)
|
||||
execjs
|
||||
json
|
||||
bcrypt (3.1.10)
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
blankslate (3.1.3)
|
||||
@ -73,7 +74,7 @@ GEM
|
||||
jbuilder (2.4.0)
|
||||
activesupport (>= 3.0.0, < 5.1)
|
||||
multi_json (~> 1.2)
|
||||
jquery-rails (4.0.5)
|
||||
jquery-rails (4.1.0)
|
||||
rails-dom-testing (~> 1.0)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
@ -122,7 +123,7 @@ GEM
|
||||
activesupport (= 4.2.5)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rake (10.4.2)
|
||||
rake (10.5.0)
|
||||
ref (2.0.0)
|
||||
rspec-core (3.4.1)
|
||||
rspec-support (~> 3.4.0)
|
||||
@ -185,6 +186,7 @@ PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
bcrypt (~> 3.1.7)
|
||||
bootstrap-sass (~> 3.3.6)
|
||||
byebug
|
||||
cocoon (~> 1.2.6)
|
||||
@ -202,3 +204,6 @@ DEPENDENCIES
|
||||
uglifier (>= 1.3.0)
|
||||
unitwise (~> 2.0.0)
|
||||
web-console (~> 2.0)
|
||||
|
||||
BUNDLED WITH
|
||||
1.11.2
|
||||
|
@ -2,4 +2,31 @@ class ApplicationController < ActionController::Base
|
||||
# Prevent CSRF attacks by raising an exception.
|
||||
# For APIs, you may want to use :null_session instead.
|
||||
protect_from_forgery with: :exception
|
||||
|
||||
def ensure_valid_user
|
||||
if current_user.nil?
|
||||
flash[:warning] = "You must login"
|
||||
redirect_to login_path
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_admin_user
|
||||
unless current_user && current_user.is_admin?
|
||||
flash[:warning] = "You must login as an admin"
|
||||
redirect_to login_path
|
||||
end
|
||||
end
|
||||
|
||||
def current_user
|
||||
@current_user ||= User.find(session[:user_id]) if session[:user_id]
|
||||
end
|
||||
helper_method :current_user
|
||||
|
||||
def set_current_user(user)
|
||||
if user
|
||||
session[:user_id] = user.id
|
||||
else
|
||||
session[:user_id] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,9 @@
|
||||
class IngredientsController < ApplicationController
|
||||
|
||||
before_action :set_ingredient, only: [:edit, :update, :destroy]
|
||||
|
||||
before_filter :ensure_valid_user, only: [:new, :edit, :create, :update, :destroy]
|
||||
|
||||
# GET /ingredients
|
||||
# GET /ingredients.json
|
||||
def index
|
||||
|
@ -1,8 +1,10 @@
|
||||
class RecipesController < ApplicationController
|
||||
|
||||
before_action :set_recipe, only: [:show, :edit, :update, :destroy, :scale]
|
||||
|
||||
before_filter :ensure_valid_user, only: [:new, :edit, :create, :update, :destroy]
|
||||
|
||||
# GET /recipes
|
||||
# GET /recipes.json
|
||||
def index
|
||||
@recipes = Recipe.active
|
||||
end
|
||||
@ -29,48 +31,34 @@ class RecipesController < ApplicationController
|
||||
end
|
||||
|
||||
# POST /recipes
|
||||
# POST /recipes.json
|
||||
def create
|
||||
@recipe = Recipe.new(recipe_params)
|
||||
@recipe.user = current_user
|
||||
|
||||
respond_to do |format|
|
||||
if @recipe.save
|
||||
format.html { redirect_to @recipe, notice: 'Recipe was successfully created.' }
|
||||
format.json { render :show, status: :created, location: @recipe }
|
||||
redirect_to @recipe, notice: 'Recipe was successfully created.'
|
||||
else
|
||||
format.html { render :new }
|
||||
format.json { render json: @recipe.errors, status: :unprocessable_entity }
|
||||
end
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
# PATCH/PUT /recipes/1
|
||||
# PATCH/PUT /recipes/1.json
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @recipe.update(recipe_params)
|
||||
format.html { redirect_to @recipe, notice: 'Recipe was successfully updated.' }
|
||||
format.json { render :show, status: :ok, location: @recipe }
|
||||
redirect_to @recipe, notice: 'Recipe was successfully updated.'
|
||||
else
|
||||
format.html { render :edit }
|
||||
format.json { render json: @recipe.errors, status: :unprocessable_entity }
|
||||
end
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /recipes/1
|
||||
# DELETE /recipes/1.json
|
||||
def destroy
|
||||
@recipe.deleted = true
|
||||
|
||||
respond_to do |format|
|
||||
if @recipe.save
|
||||
format.html { redirect_to recipes_url, notice: 'Recipe was successfully destroyed.' }
|
||||
format.json { head :no_content }
|
||||
redirect_to recipes_url, notice: 'Recipe was successfully destroyed.'
|
||||
else
|
||||
format.html { redirect_to recipes_url, error: 'Recipe could not be destroyed.' }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
redirect_to recipes_url, error: 'Recipe could not be destroyed.'
|
||||
end
|
||||
end
|
||||
|
||||
|
60
app/controllers/users_controller.rb
Normal file
60
app/controllers/users_controller.rb
Normal file
@ -0,0 +1,60 @@
|
||||
class UsersController < ApplicationController
|
||||
|
||||
before_filter :ensure_valid_user, except: [:login, :verify_login, :new, :create]
|
||||
|
||||
def login
|
||||
|
||||
end
|
||||
|
||||
def logout
|
||||
set_current_user(nil)
|
||||
session.destroy
|
||||
flash[:notice] = "Logged out"
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
def verify_login
|
||||
if user = User.authenticate(params[:email], params[:password])
|
||||
set_current_user(user)
|
||||
flash[:notice] = "Welcome, #{user.full_name}"
|
||||
redirect_to root_path
|
||||
else
|
||||
flash[:error] = "Invalid credentials"
|
||||
render :login
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@user = User.new
|
||||
end
|
||||
|
||||
def create
|
||||
@user = User.new(user_params)
|
||||
|
||||
if @user.save
|
||||
set_current_user(@user)
|
||||
redirect_to root_path, notice: 'User was successfully created.'
|
||||
else
|
||||
render action: :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@user = current_user
|
||||
end
|
||||
|
||||
def update
|
||||
@user = current_user
|
||||
if @user.update(user_params)
|
||||
redirect_to root_path, notice: 'User account updated'
|
||||
else
|
||||
render action: 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:username, :email, :full_name, :password, :password_confirmation)
|
||||
end
|
||||
end
|
@ -11,7 +11,27 @@ module ApplicationHelper
|
||||
]
|
||||
end
|
||||
|
||||
def nav_item(name, url, controller)
|
||||
def profile_nav_items
|
||||
if current_user
|
||||
[content_tag('li', class: 'dropdown') do
|
||||
li_cnt = ''.html_safe
|
||||
|
||||
li_cnt << link_to('#', class: 'dropdown-toggle', data: {toggle: 'dropdown'}, role: 'button') do
|
||||
''.html_safe << "#{current_user.display_name}" << content_tag('span', '', class: 'caret')
|
||||
end
|
||||
|
||||
li_cnt << content_tag('ul', class: 'dropdown-menu') do
|
||||
''.html_safe << nav_item('Profile', edit_user_path) << nav_item('Logout', logout_path)
|
||||
end
|
||||
|
||||
li_cnt
|
||||
end]
|
||||
else
|
||||
[nav_item('Login', login_path)]
|
||||
end
|
||||
end
|
||||
|
||||
def nav_item(name, url, controller = nil)
|
||||
content_tag('li', link_to(name, url), class: active_for_controller(controller))
|
||||
end
|
||||
|
||||
|
@ -2,6 +2,7 @@ class Recipe < ActiveRecord::Base
|
||||
|
||||
has_many :recipe_ingredients, -> { order :sort_order }, inverse_of: :recipe, dependent: :destroy
|
||||
has_many :recipe_steps, -> { order :sort_order }, inverse_of: :recipe, dependent: :destroy
|
||||
belongs_to :user
|
||||
|
||||
scope :active, -> { where('deleted <> ? OR deleted IS NULL', true) }
|
||||
|
||||
|
15
app/models/user.rb
Normal file
15
app/models/user.rb
Normal file
@ -0,0 +1,15 @@
|
||||
class User < ActiveRecord::Base
|
||||
|
||||
has_secure_password
|
||||
|
||||
validates :username, presence: true, uniqueness: { case_sensitive: false }
|
||||
|
||||
def self.authenticate(email, password)
|
||||
find_by_email(email).try(:authenticate, password)
|
||||
end
|
||||
|
||||
def display_name
|
||||
self.full_name.present? ? self.full_name : self.username
|
||||
end
|
||||
|
||||
end
|
@ -5,17 +5,17 @@
|
||||
<%= render partial: 'shared/error_list', locals: {model: @ingredient} %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :name %>
|
||||
<%= f.label :name, class: 'control-label' %>
|
||||
<%= f.text_field :name, class: 'form-control', autofocus: true %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :density %>
|
||||
<%= f.label :density, class: 'control-label' %>
|
||||
<%= f.text_field :density, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :notes %>
|
||||
<%= f.label :notes, class: 'control-label' %>
|
||||
<%= f.text_area :notes, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
|
@ -4,6 +4,10 @@
|
||||
<h1>Ingredients</h1>
|
||||
</div>
|
||||
|
||||
<% if @ingredients.empty? %>
|
||||
<p>No Ingredients</p>
|
||||
<% else %>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -23,10 +27,11 @@
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
<br>
|
||||
<br/>
|
||||
|
||||
<%= link_to 'New Ingredient', new_ingredient_path, class: 'btn btn-primary' %>
|
||||
<%= link_to 'New Ingredient', new_ingredient_path, class: 'btn btn-default' %>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,4 +0,0 @@
|
||||
json.array!(@ingredients) do |ingredient|
|
||||
json.extract! ingredient, :id
|
||||
json.url ingredient_url(ingredient, format: :json)
|
||||
end
|
@ -29,6 +29,11 @@
|
||||
<%= li %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<% profile_nav_items.each do |li| %>
|
||||
<%= li %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</nav>
|
||||
|
@ -1,4 +0,0 @@
|
||||
json.array!(@recipes) do |recipe|
|
||||
json.extract! recipe, :id
|
||||
json.url recipe_url(recipe, format: :json)
|
||||
end
|
@ -1 +0,0 @@
|
||||
json.extract! @recipe, :id, :created_at, :updated_at
|
30
app/views/users/_form.html.erb
Normal file
30
app/views/users/_form.html.erb
Normal file
@ -0,0 +1,30 @@
|
||||
<%= form_for(@user, url: user_path) do |f| %>
|
||||
|
||||
<%= render partial: 'shared/error_list', locals: {model: @user} %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :username, class: 'control-label' %>
|
||||
<%= f.text_field :username, class: 'form-control' %>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :full_name, 'Name', class: 'control-label' %>
|
||||
<%= f.text_field :full_name, class: 'form-control' %>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :email, class: 'control-label' %>
|
||||
<%= f.text_field :email, class: 'form-control' %>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :password, class: 'control-label' %>
|
||||
<%= f.password_field :password, class: 'form-control' %>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<%= f.label :password_confirmation, class: 'control-label' %>
|
||||
<%= f.password_field :password_confirmation, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit class: 'btn btn-primary' %>
|
||||
<%= link_to "Back", root_path, class: 'btn btn-default' %>
|
||||
</div>
|
||||
<% end %>
|
11
app/views/users/edit.html.erb
Normal file
11
app/views/users/edit.html.erb
Normal file
@ -0,0 +1,11 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
|
||||
<div class="page-header">
|
||||
<h1>Edit Your Profile</h1>
|
||||
</div>
|
||||
|
||||
<%= render partial: 'form' %>
|
||||
|
||||
</div>
|
||||
</div>
|
31
app/views/users/login.html.erb
Normal file
31
app/views/users/login.html.erb
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
|
||||
<div class="page-header">
|
||||
<h1>Parsley Login</h1>
|
||||
</div>
|
||||
|
||||
|
||||
<%= form_tag(login_path, :method => :post) do %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= label_tag :email, "Email", class: 'control-label' %>
|
||||
<%= text_field_tag :email, nil, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= label_tag :password, "Password", class: 'control-label' %>
|
||||
<%= password_field_tag :password, nil, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<%= submit_tag("Login", class: 'btn btn-primary') %>
|
||||
<% end %>
|
||||
|
||||
<br />
|
||||
|
||||
<%= link_to "Create an Account", new_user_path, class: 'btn btn-default' %>
|
||||
|
||||
</div>
|
||||
</div>
|
11
app/views/users/new.html.erb
Normal file
11
app/views/users/new.html.erb
Normal file
@ -0,0 +1,11 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
|
||||
<div class="page-header">
|
||||
<h1>Create user</h1>
|
||||
</div>
|
||||
|
||||
<%= render partial: 'form' %>
|
||||
|
||||
</div>
|
||||
</div>
|
@ -16,6 +16,12 @@ Rails.application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
resource :user, only: [:new, :create, :edit, :update]
|
||||
|
||||
get '/login' => 'users#login', as: :login
|
||||
post '/login' => 'users#verify_login'
|
||||
get '/logout' => 'users#logout', as: :logout
|
||||
|
||||
root 'recipes#index'
|
||||
|
||||
|
||||
|
15
db/migrate/20160119212055_create_users.rb
Normal file
15
db/migrate/20160119212055_create_users.rb
Normal file
@ -0,0 +1,15 @@
|
||||
class CreateUsers < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :users do |t|
|
||||
t.string :username
|
||||
t.string :email
|
||||
t.string :full_name
|
||||
t.string :password_digest
|
||||
t.boolean :admin
|
||||
|
||||
t.timestamps null: false
|
||||
end
|
||||
|
||||
add_column :recipes, :user_id, :integer
|
||||
end
|
||||
end
|
13
db/schema.rb
13
db/schema.rb
@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160119012704) do
|
||||
ActiveRecord::Schema.define(version: 20160119212055) do
|
||||
|
||||
create_table "ingredients", force: :cascade do |t|
|
||||
t.string "name"
|
||||
@ -55,6 +55,17 @@ ActiveRecord::Schema.define(version: 20160119012704) do
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "deleted"
|
||||
t.integer "user_id"
|
||||
end
|
||||
|
||||
create_table "users", force: :cascade do |t|
|
||||
t.string "username"
|
||||
t.string "email"
|
||||
t.string "full_name"
|
||||
t.string "password_digest"
|
||||
t.boolean "admin"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
end
|
||||
|
10
spec/factories/users.rb
Normal file
10
spec/factories/users.rb
Normal file
@ -0,0 +1,10 @@
|
||||
FactoryGirl.define do
|
||||
factory :user do
|
||||
username "MyString"
|
||||
email "MyString"
|
||||
full_name "MyString"
|
||||
password_digest "MyString"
|
||||
admin false
|
||||
end
|
||||
|
||||
end
|
5
spec/models/user_spec.rb
Normal file
5
spec/models/user_spec.rb
Normal file
@ -0,0 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe User, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
Loading…
Reference in New Issue
Block a user