diff options
| author | mo khan <mo@mokhan.ca> | 2015-05-18 22:39:54 -0700 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2015-05-18 22:40:03 -0700 |
| commit | eeb979980945e6946f3471be84b791eebc972c02 (patch) | |
| tree | 755c460b8f48ea462ac07d82c7159ffed671a4db | |
| parent | b247132cdd30f99b7960432558dd6e0784bbbd1c (diff) | |
| parent | 6bc4fbcae691a5118c9a792f9b8a241031c000ef (diff) | |
merge with supply.
92 files changed, 1717 insertions, 338 deletions
@@ -32,6 +32,7 @@ gem 'bcrypt', '~> 3.1.7' # Use Puma as the app server gem 'puma' gem 'rack-timeout' +gem 'scale' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development @@ -46,6 +47,8 @@ group :development, :test do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' + gem 'spring-commands-rspec' + gem 'spring-commands-teaspoon' gem 'rspec-rails' gem 'foreman' gem 'i18n-tasks' @@ -53,6 +56,8 @@ group :development, :test do gem 'factory_girl_rails' gem 'ffaker' gem 'database_cleaner' + gem 'teaspoon' + gem 'meta_request' end group :production do diff --git a/Gemfile.lock b/Gemfile.lock index a56e527..1b7bda6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -37,14 +37,17 @@ GEM thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) arel (6.0.0) - bcrypt (3.1.9) + axiom-types (0.1.1) + descendants_tracker (~> 0.0.4) + ice_nine (~> 0.11.0) + thread_safe (~> 0.3, >= 0.3.1) + bcrypt (3.1.10) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) builder (3.2.2) - byebug (3.5.1) - columnize (~> 0.8) - debugger-linecache (~> 1.2) - slop (~> 3.6) + byebug (4.0.5) + columnize (= 0.9.0) + callsite (0.0.11) capybara (2.4.4) mime-types (>= 1.16) nokogiri (>= 1.3.3) @@ -52,93 +55,105 @@ GEM rack-test (>= 0.5.4) xpath (~> 2.0) cliver (0.3.2) + coercible (1.0.0) + descendants_tracker (~> 0.0.1) coffee-rails (4.1.0) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) - coffee-script (2.3.0) + coffee-script (2.4.1) coffee-script-source execjs - coffee-script-source (1.8.0) + coffee-script-source (1.9.1.1) columnize (0.9.0) - coveralls (0.7.3) + coveralls (0.8.0) multi_json (~> 1.10) - rest-client (~> 1.7) + rest-client (>= 1.6.8, < 2) simplecov (~> 0.9.1) term-ansicolor (~> 1.3) thor (~> 0.19.1) - database_cleaner (1.4.0) + database_cleaner (1.4.1) debug_inspector (0.0.2) - debugger-linecache (1.2.0) + descendants_tracker (0.0.4) + thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.2.5) docile (1.1.5) - dotenv (1.0.2) - dotenv-rails (1.0.2) - dotenv (= 1.0.2) + domain_name (0.5.23) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.0.1) + dotenv-rails (2.0.1) + dotenv (= 2.0.1) easy_translate (0.5.0) json thread thread_safe email_validator (1.5.0) activemodel + equalizer (0.0.11) erubis (2.7.0) - execjs (2.2.2) + execjs (2.5.2) factory_girl (4.5.0) activesupport (>= 3.0.0) factory_girl_rails (4.5.0) factory_girl (~> 4.5.0) railties (>= 3.0.0) - ffaker (1.31.0) - foreman (0.76.0) - dotenv (~> 1.0.2) + ffaker (2.0.0) + foreman (0.78.0) thor (~> 0.19.1) - foundation-rails (5.4.5.0) + foundation-rails (5.5.1.2) railties (>= 3.1.0) - sass (>= 3.2.0) - globalid (0.3.0) + sass (>= 3.3.0, < 3.5) + globalid (0.3.5) activesupport (>= 4.1.0) - highline (1.6.21) - hike (1.2.3) + highline (1.7.1) + http-cookie (1.0.2) + domain_name (~> 0.5) i18n (0.7.0) - i18n-tasks (0.7.10) + i18n-tasks (0.8.2) activesupport easy_translate (>= 0.5.0) erubis highline i18n - slop (>= 3.5.0) term-ansicolor terminal-table - jbuilder (2.2.6) + ice_nine (0.11.1) + jbuilder (2.2.13) activesupport (>= 3.0.0, < 5) multi_json (~> 1.2) - jquery-rails (4.0.2) + jquery-rails (4.0.3) rails-dom-testing (~> 1.0) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (1.8.1) + json (1.8.2) loofah (2.0.1) nokogiri (>= 1.5.9) mail (2.6.3) mime-types (>= 1.16, < 3) + meta_request (0.3.4) + callsite (~> 0.0, >= 0.0.11) + rack-contrib (~> 1.1) + railties (>= 3.0.0, < 5.0.0) mime-types (2.4.3) - mini_portile (0.6.1) - minitest (5.5.0) - multi_json (1.10.1) - netrc (0.10.2) - nokogiri (1.6.5) + mini_portile (0.6.2) + minitest (5.5.1) + multi_json (1.11.0) + netrc (0.10.3) + nokogiri (1.6.6.2) mini_portile (~> 0.6.0) - pg (0.17.1) - poltergeist (1.5.1) + pg (0.18.1) + poltergeist (1.6.0) capybara (~> 2.1) cliver (~> 0.3.1) multi_json (~> 1.0) websocket-driver (>= 0.2.0) - puma (2.11.1) + puma (2.11.2) rack (>= 1.1, < 2.0) rack (1.6.0) - rack-test (0.6.2) + rack-contrib (1.2.0) + rack (>= 0.9.1) + rack-test (0.6.3) rack (>= 1.0) - rack-timeout (0.2.0) + rack-timeout (0.2.4) rails (4.2.0) actionmailer (= 4.2.0) actionpack (= 4.2.0) @@ -152,16 +167,16 @@ GEM sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.5) + rails-dom-testing (1.0.6) activesupport (>= 4.2.0.beta, < 5.0) nokogiri (~> 1.6.0) rails-deprecated_sanitizer (>= 1.0.1) - rails-html-sanitizer (1.0.1) + rails-html-sanitizer (1.0.2) loofah (~> 2.0) rails_12factor (0.0.3) rails_serve_static_assets rails_stdout_logging - rails_serve_static_assets (0.0.3) + rails_serve_static_assets (0.0.4) rails_stdout_logging (0.0.3) railties (4.2.0) actionpack (= 4.2.0) @@ -170,75 +185,89 @@ GEM thor (>= 0.18.1, < 2.0) rake (10.4.2) rdoc (4.2.0) - json (~> 1.4) - rest-client (1.7.2) + rest-client (1.8.0) + http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 3.0) netrc (~> 0.7) - rspec-core (3.1.7) - rspec-support (~> 3.1.0) - rspec-expectations (3.1.2) + rspec-core (3.2.3) + rspec-support (~> 3.2.0) + rspec-expectations (3.2.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.1.0) - rspec-mocks (3.1.3) - rspec-support (~> 3.1.0) - rspec-rails (3.1.0) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.1.0) - rspec-expectations (~> 3.1.0) - rspec-mocks (~> 3.1.0) - rspec-support (~> 3.1.0) - rspec-support (3.1.2) - sass (3.4.9) - sass-rails (5.0.0) + rspec-support (~> 3.2.0) + rspec-mocks (3.2.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.2.0) + rspec-rails (3.2.1) + actionpack (>= 3.0, < 4.3) + activesupport (>= 3.0, < 4.3) + railties (>= 3.0, < 4.3) + rspec-core (~> 3.2.0) + rspec-expectations (~> 3.2.0) + rspec-mocks (~> 3.2.0) + rspec-support (~> 3.2.0) + rspec-support (3.2.2) + sass (3.4.13) + sass-rails (5.0.3) railties (>= 4.0.0, < 5.0) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (~> 1.1) + scale (0.1.3) + nokogiri (~> 1.6.6) + virtus (~> 1.0) sdoc (0.4.1) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) - simplecov (0.9.1) + simplecov (0.9.2) docile (~> 1.1.0) multi_json (~> 1.0) - simplecov-html (~> 0.8.0) - simplecov-html (0.8.0) - slop (3.6.0) - spring (1.2.0) - sprockets (2.12.3) - hike (~> 1.2) - multi_json (~> 1.0) + simplecov-html (~> 0.9.0) + simplecov-html (0.9.0) + spring (1.3.4) + spring-commands-rspec (1.0.4) + spring (>= 0.9.1) + spring-commands-teaspoon (0.0.2) + spring (>= 0.9.1) + sprockets (3.0.0) rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.2.2) + sprockets-rails (2.2.4) actionpack (>= 3.0) activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) + teaspoon (0.9.1) + railties (>= 3.2.5, < 5) term-ansicolor (1.3.0) tins (~> 1.0) terminal-table (1.4.5) thor (0.19.1) - thread (0.1.4) - thread_safe (0.3.4) + thread (0.2.0) + thread_safe (0.3.5) tilt (1.4.1) - tins (1.3.3) + tins (1.3.5) turbolinks (2.5.3) coffee-rails tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (2.6.0) + uglifier (2.7.1) execjs (>= 0.3.0) json (>= 1.8.0) - web-console (2.0.0) - activemodel (~> 4.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.6) + virtus (1.0.5) + axiom-types (~> 0.1) + coercible (~> 1.0) + descendants_tracker (~> 0.0, >= 0.0.3) + equalizer (~> 0.0, >= 0.0.9) + web-console (2.1.2) + activemodel (>= 4.0) binding_of_caller (>= 0.7.2) - railties (~> 4.0) + railties (>= 4.0) sprockets-rails (>= 2.0, < 4.0) - websocket-driver (0.5.1) + websocket-driver (0.5.4) websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.1) + websocket-extensions (0.1.2) xpath (2.0.0) nokogiri (~> 1.3) @@ -260,6 +289,7 @@ DEPENDENCIES i18n-tasks jbuilder (~> 2.0) jquery-rails + meta_request pg poltergeist puma @@ -268,8 +298,12 @@ DEPENDENCIES rails_12factor rspec-rails sass-rails (~> 5.0) + scale sdoc (~> 0.4.0) spring + spring-commands-rspec + spring-commands-teaspoon + teaspoon turbolinks uglifier (>= 1.3.0) web-console (~> 2.0) @@ -4,3 +4,5 @@ require File.expand_path('../config/application', __FILE__) Rails.application.load_tasks + +task default: [:spec, :teaspoon] diff --git a/app/assets/images/sprite.svg b/app/assets/images/sprite.svg new file mode 100644 index 0000000..cc6b842 --- /dev/null +++ b/app/assets/images/sprite.svg @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="feather" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="82.515px" height="266.693px" viewBox="0 0 82.515 266.693" style="enable-background:new 0 0 82.515 266.693;"
+ xml:space="preserve">
+<g>
+ <path d="M33.115,261.74c-0.158-0.806-15.738-75.844-7.023-128.607l3.906,0.43c-8.646,52.359,6.77,132.328,6.928,133.131
+ L33.115,261.74L33.115,261.74z"/>
+</g>
+<path d="M82.506,52.314C82.169,6.108,65.462-5.734,47.971,2.374c-0.593,2.912-1.6,6.565-3.174,11.16v-0.5
+ c0,0-1.115-3.625-1.972-7.713C27.238,15.903,12.24,41.192,8.851,71.033C0.812,141.791-11.148,199.073,22.19,203.7
+ c3.645,0.506,6.667,0,6.667,0c9.487-0.842,25.445-0.214,38.289-42.974c2.248-13.861,4.699-30.531,4.136-34.192c-1-6.5,2-7,2.5-12.5
+ s0.5-15.5,3-30s6.5-14,4.5-23C80.555,57.76,81.285,54.951,82.506,52.314z"/>
+<g>
+ <g>
+ <path d="M29.497,220.616c0,0-1.179,2.75-5.505,2.224c0,0,3.529,1.371,6.33-1.668L29.497,220.616z"/>
+ </g>
+ <g>
+ <path d="M28.738,219.737c0,0-1.962,3.24-7.292,1.817c0,0,4.183,2.341,8.229-0.975L28.738,219.737z"/>
+ </g>
+ <g>
+ <path d="M27.943,218.501c0,0-3.031,3.717-9.461,0.994c0,0,4.831,3.671,10.486,0.228L27.943,218.501z"/>
+ </g>
+ <g>
+ <path d="M27.163,216.813c0,0-4.454,4.125-12.035-0.42c0,0,5.408,5.452,13.104,2.132L27.163,216.813z"/>
+ </g>
+ <g>
+ <path d="M26.483,214.56c0,0-6.31,4.386-15.012-2.647c0,0,5.819,7.787,16.05,4.98L26.483,214.56z"/>
+ </g>
+ <g>
+ <path d="M26.028,211.616c0,0-8.681,4.386-18.351-5.963c0,0,5.922,10.786,19.241,9.07L26.028,211.616z"/>
+ </g>
+ <g>
+ <path d="M25.976,207.845c0,0-11.654,3.968-21.952-10.708c0,0,5.523,14.564,22.521,14.76L25.976,207.845z"/>
+ </g>
+ <g>
+ <path d="M26.575,203.109c0,0-15.308,2.921-25.63-17.29c0,0,4.357,19.23,25.63,22.47V203.109z"/>
+ </g>
+</g>
+<path d="M27.49,203.368c0,0,21.625,2.5,31.792-19.5c0,0-9.753,24.198-31.271,24.421L27.49,203.368z"/>
+<g>
+ <g>
+ <path d="M30.582,225.85c0,0,4.442,3.239,9.978-1.136c0,0-4.057,4.84-10.348,2.624L30.582,225.85z"/>
+ </g>
+ <g>
+ <path d="M30.587,223.619c0,0,5.821,3.652,12.343-2.285c0,0-4.636,6.389-12.674,4.174L30.587,223.619z"/>
+ </g>
+ <g>
+ <path d="M30.4,220.836c0,0,7.578,4.047,15.192-3.926c0,0-5.225,8.37-15.44,6.31L30.4,220.836z"/>
+ </g>
+ <g>
+ <path d="M29.924,217.383c0,0,9.802,4.386,18.602-6.22c0,0-5.785,10.893-18.704,9.214L29.924,217.383z"/>
+ </g>
+ <g>
+ <path d="M29.03,213.119c0,0,12.605,4.614,22.653-9.378c0,0-6.264,14.088-22.519,13.12L29.03,213.119z"/>
+ </g>
+ <g>
+ <path d="M27.542,207.878c0,0,16.121,4.655,27.429-13.668c0,0-6.582,18.112-26.936,18.323L27.542,207.878z"/>
+ </g>
+</g>
+<path d="M30.69,227.048c0,0,2.161,4.327,8.256,3.148c0,0-5.127,2.141-9.147-2.135L30.69,227.048z"/>
+</svg>
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index c822f93..4675393 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -14,6 +14,7 @@ //= require jquery_ujs //= require foundation //= require turbolinks +//= require_self //= require_tree . -$(function(){ $(document).foundation(); }); +var SupplyCrow = SupplyCrow || {}; diff --git a/app/assets/javascripts/items.js b/app/assets/javascripts/items.js new file mode 100644 index 0000000..bb7108c --- /dev/null +++ b/app/assets/javascripts/items.js @@ -0,0 +1,10 @@ +$(function(){ + $(".delete_stub").click(function(){ + $(this).hide(); + $(".delete_form").show(); + }); + $(".delete_form .cancel").click(function(){ + $(this).parent("form").hide(); + $(".delete_stub").show(); + }); +}); diff --git a/app/assets/javascripts/models/calculator.js.coffee b/app/assets/javascripts/models/calculator.js.coffee new file mode 100644 index 0000000..384ea67 --- /dev/null +++ b/app/assets/javascripts/models/calculator.js.coffee @@ -0,0 +1,3 @@ +class SupplyCrow.Calculator + add: (x, y) -> + x + y diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index c8b8e57..2a93917 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -10,8 +10,7 @@ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new * file per style scope. * - *= require_tree . *= require_self - *= require foundation_and_overrides - */ + +@import "**/*"; diff --git a/app/assets/stylesheets/global.scss b/app/assets/stylesheets/global.scss index c0d967a..c5a13de 100644 --- a/app/assets/stylesheets/global.scss +++ b/app/assets/stylesheets/global.scss @@ -1,13 +1,72 @@ +@import url(//fonts.googleapis.com/css?family=Playfair+Display:900); + +/* ---------------------------------------------- */ +/* Mixins --------------------------------------- */ +/* ---------------------------------------------- */ +@mixin responsive-svg($svgwidth, $svgheight, $containerwidth) { + height: 0; + margin: 0 auto; + padding-top: #{($svgheight/$svgwidth)*$containerwidth}; + position: relative; + width: $containerwidth; + + svg { + left: 0; + position: absolute; + top: 0; + } +} + +/* ---------------------------------------------- */ +/* Branding ------------------------------------- */ +/* ---------------------------------------------- */ +header { + padding: 0.5em 0; + + h1 { + font-family: 'Playfair Display', serif; + } + + .svg-container { + @include responsive-svg(10, 20, 0.85em); // (width, height, containerWidth) + } + + img { + margin: 0 0.15em 0 0; + width: 18px; + } +} + +nav h1 { + font-family: 'Playfair Display', serif; + text-transform: none; + white-space: nowrap; +} + +nav svg { + display: inline-block; + fill: $white; + float: left; + margin: 5px 8px 0 20px; + position: relative; + width: 12px; + z-index: 100; +} /* ---------------------------------------------- */ /* Buttons -------------------------------------- */ /* ---------------------------------------------- */ -.button.bare, .button.bare:hover, .button.bare:active, -.button.bare:visited, .button.bare:focus { - background-color: transparent; - border-color: transparent; - padding-right: 1.5rem; - padding-left: 1.5rem; +.button.bare { + &:hover, + &:active, + &:visited, + &:focus { + background-color: transparent; + border-color: transparent; + padding-left: 1.5rem; + padding-right: 1.5rem; + } + + &:hover { + text-decoration: underline; + } } -.button.bare:hover { - text-decoration: underline; -}
\ No newline at end of file diff --git a/app/assets/stylesheets/items.scss b/app/assets/stylesheets/items.scss new file mode 100644 index 0000000..e5a3a2a --- /dev/null +++ b/app/assets/stylesheets/items.scss @@ -0,0 +1,7 @@ +.delete_stub { + display: block; +} + +.delete_form { + display: none; +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9352b61..8c30104 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,6 +2,8 @@ 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 + before_action :authenticate! + rescue_from ActiveRecord::RecordNotFound, with: :record_not_found protected @@ -9,7 +11,22 @@ class ApplicationController < ActionController::Base session[:user_id] = user.id end + def current_user + @current_user ||= User.find(session[:user_id]) + end + def translate(key) I18n.translate("#{params[:controller]}.#{params[:action]}#{key}") end + + def authenticate! + return if session[:user_id].present? && current_user.present? + redirect_to new_session_path + rescue + redirect_to new_session_path + end + + def record_not_found + render text: "404 Not Found", status: 404 + end end diff --git a/app/controllers/items_controller.rb b/app/controllers/items_controller.rb new file mode 100644 index 0000000..c0e652e --- /dev/null +++ b/app/controllers/items_controller.rb @@ -0,0 +1,51 @@ +class ItemsController < ApplicationController + def index + @items = current_user.items + @item = Item.new + end + + def show + @item = current_user.items.find(params[:id]) + end + + def new + @item = params[:item].present? ? Item.new(secure_params) : Item.new + end + + def edit + @item = current_user.items.find(params[:id]) + end + + def create + @item = current_user.items.build(secure_params) + if @item.save + redirect_to dashboard_path + else + flash[:warning] = @item.errors.full_messages + render :new + end + end + + def update + item = current_user.items.find(params[:id]) + item.update!(secure_params) + redirect_to dashboard_path + end + + def destroy + current_user.items.destroy(params[:id]) + redirect_to dashboard_path + end + + private + + def secure_params + params.require(:item).permit( + :name, + :description, + :serial_number, + :purchase_price, + :purchased_at, + ) + end +end diff --git a/app/controllers/public_controller.rb b/app/controllers/public_controller.rb new file mode 100644 index 0000000..57b1cff --- /dev/null +++ b/app/controllers/public_controller.rb @@ -0,0 +1,4 @@ +class PublicController < ApplicationController + layout "public" + skip_before_action :authenticate! +end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index 74e5408..cb8f3dd 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -1,6 +1,4 @@ -class RegistrationsController < ApplicationController - layout "public" - +class RegistrationsController < PublicController def new @user = User.new end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 5cba67e..5a20c27 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,10 +1,6 @@ -class SessionsController < ApplicationController - - layout "public" - +class SessionsController < PublicController def create - user = User.authenticate(params[:user][:username], params[:user][:password]) - if user.present? + if user = User.authenticate(params[:user][:username], params[:user][:password]) session[:user_id] = user.id redirect_to dashboard_path else @@ -12,15 +8,13 @@ class SessionsController < ApplicationController redirect_to new_session_path end end - + def new @user = User.new - end - + def destroy reset_session() redirect_to root_path end - end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index ef68714..66e5df5 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,6 +1,6 @@ class UserMailer < ApplicationMailer def registration_email(user) @username = user.username - mail to: user.email, subject: "Welcome to Supply." + mail to: user.email, subject: "Welcome to Supply Crow." end end diff --git a/app/models/item.rb b/app/models/item.rb new file mode 100644 index 0000000..36b5547 --- /dev/null +++ b/app/models/item.rb @@ -0,0 +1,6 @@ +class Item < ActiveRecord::Base + belongs_to :user + + validates :user, presence: true + validates :name, presence: true +end diff --git a/app/models/user.rb b/app/models/user.rb index 072d1bf..89cf354 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,5 +1,6 @@ class User < ActiveRecord::Base has_secure_password + has_many :items USERNAME_REGEX=/\A[-a-z0-9_.]*\z/i validates :username, presence: true, format: { with: USERNAME_REGEX }, uniqueness: true diff --git a/app/views/items/_form.html.erb b/app/views/items/_form.html.erb new file mode 100644 index 0000000..1d14cec --- /dev/null +++ b/app/views/items/_form.html.erb @@ -0,0 +1,31 @@ +<%= form_for(@item) do |f| %> + <div class="small-12 columns"> + <%= f.label :name, t('.name') %> + <%= f.text_field :name %> + </div> + <div class="small-12 columns"> + <%= f.label :description, t('.description') %> + <%= f.text_area :description %> + </div> + <div class="small-12 columns"> + <%= f.label :serial_number, t('.serial_number') %> + <%= f.text_field :serial_number %> + </div> + <div class="small-12 columns"> + <div class="row"> + <div class="small-6 columns"> + <%= f.label :purchase_price, t('.purchase_price') %> + <%= f.text_field :purchase_price %> + </div> + <div class="small-6 columns"> + <%= f.label :purchased_at, t('.purchase_date') do %> + <%= t('.purchased_at') %> + <%= f.date_field :purchased_at %> + <% end %> + </div> + </div> + </div> + <div class="small-12 columns"> + <%= f.submit t('.create_button'), class: 'button' %> + </div> +<% end %> diff --git a/app/views/items/edit.html.erb b/app/views/items/edit.html.erb new file mode 100644 index 0000000..d24e6a3 --- /dev/null +++ b/app/views/items/edit.html.erb @@ -0,0 +1,6 @@ +<h1>Editing Item</h1> + +<%= render 'form' %> + +<%= link_to 'Show', @item %> | +<%= link_to 'Back', items_path %> diff --git a/app/views/items/index.html.erb b/app/views/items/index.html.erb new file mode 100644 index 0000000..2d8a236 --- /dev/null +++ b/app/views/items/index.html.erb @@ -0,0 +1,51 @@ +<div class="row"> + <!-- Side Bar --> + <div class="large-4 small-12 columns"> + <div class="hide-for-small panel"> + <div class="row"> + <%= form_for(@item, url: new_item_path, method: :get) do |f| %> + <div class="small-12 columns"> + <label><%= t('.item_name') %> + <%= f.text_field :name %> + </label> + </div> <!-- /.small-12 --> + <div class="small-12 columns"> + <%= f.submit t('.new_item_button'), class: 'button' %> + </div> <!-- /.small-12 --> + <% end %> + </div> + </div> + + <a href="#"> + <div class="panel callout radius"> + <h6>99Â items in your cart</h6> + </div> + </a> + </div> + <!-- End Side Bar --> + + <!-- Thumbnails --> + <div class="large-8 columns"> + <div class="row"> + <% if @items.any? %> + <% @items.each do |item| %> + <div class="large-4 small-6 columns"> + <img src="http://placehold.it/1000x1000&text=Thumbnail"> + + <div class="panel"> + <h5><%= link_to item.name, item_path(item) %></h5> + <h6 class="subheader"><%= number_to_currency item.purchase_price %></h6> + </div> + </div> + <% end %> + <% else %> + <div class="small-12 columns"> + <h1>Your inventory is empty</h1> + <%= link_to 'New Item', new_item_path %> + </div> + <% end %> + </div> + <!-- End Thumbnails --> + </div> + </div> +</div> diff --git a/app/views/items/new.html.erb b/app/views/items/new.html.erb new file mode 100644 index 0000000..820e5b0 --- /dev/null +++ b/app/views/items/new.html.erb @@ -0,0 +1,7 @@ +<div class="row"> + <div class="small-12 columns"> + <h1>New Item</h1> + </div> + + <%= render 'form' %> +</div> diff --git a/app/views/items/show.html.erb b/app/views/items/show.html.erb new file mode 100644 index 0000000..1472d76 --- /dev/null +++ b/app/views/items/show.html.erb @@ -0,0 +1,33 @@ +<p id="notice"><%= notice %></p> + +<p> + <strong>Name:</strong> + <%= @item.name %> +</p> + +<p> + <strong>Description:</strong> + <%= @item.description %> +</p> + +<p> + <strong>Serial number:</strong> + <%= @item.serial_number %> +</p> + +<p> + <strong>Purchase price:</strong> + <%= @item.purchase_price %> +</p> + +<p> + <strong>Purchased at:</strong> + <%= @item.purchased_at %> +</p> + +<%= link_to t(".edit_button"), edit_item_path(@item) %> +<button class="small delete_stub"><%= t(".delete_button")%></button> +<%= form_for @item, method: :delete, html: { class: "delete_form" } do |f| %> + <%= f.submit t(".delete_confirm"), class: "small alert button" %> + <button class="small secondary button cancel" type="button"><%= t(".cancel_button")%></button> +<% end %> diff --git a/app/views/layouts/_terms_content.html.erb b/app/views/layouts/_terms_content.html.erb index bdce8fb..f393a7e 100644 --- a/app/views/layouts/_terms_content.html.erb +++ b/app/views/layouts/_terms_content.html.erb @@ -14,19 +14,19 @@ <ol type="a"> <li> Permission is granted to temporarily download one copy of the materials - (information or software) on SupplyApp's web site for personal, + (information or software) on Supply Crow's web site for personal, non-commercial transitory viewing only. This is the grant of a license, not a transfer of title, and under this license you may not: <ol type="i"> <li>modify or copy the materials;</li> <li>use the materials for any commercial purpose, or for any public display (commercial or non-commercial);</li> - <li>attempt to decompile or reverse engineer any software contained on SupplyApp's web site;</li> + <li>attempt to decompile or reverse engineer any software contained on Supply Crow's web site;</li> <li>remove any copyright or other proprietary notations from the materials; or</li> <li>transfer the materials to another person or "mirror" the materials on any other server.</li> </ol> </li> <li> - This license shall automatically terminate if you violate any of these restrictions and may be terminated by SupplyApp at any time. Upon terminating your viewing of these materials or upon the termination of this license, you must destroy any downloaded materials in your possession whether in electronic or printed format. + This license shall automatically terminate if you violate any of these restrictions and may be terminated by Supply Crow at any time. Upon terminating your viewing of these materials or upon the termination of this license, you must destroy any downloaded materials in your possession whether in electronic or printed format. </li> </ol> <h3> @@ -34,38 +34,38 @@ </h3> <ol type="a"> <li> - The materials on SupplyApp's web site are provided "as is". SupplyApp makes no warranties, expressed or implied, and hereby disclaims and negates all other warranties, including without limitation, implied warranties or conditions of merchantability, fitness for a particular purpose, or non-infringement of intellectual property or other violation of rights. Further, SupplyApp does not warrant or make any representations concerning the accuracy, likely results, or reliability of the use of the materials on its Internet web site or otherwise relating to such materials or on any sites linked to this site. + The materials on Supply Crow's web site are provided "as is". Supply Crow makes no warranties, expressed or implied, and hereby disclaims and negates all other warranties, including without limitation, implied warranties or conditions of merchantability, fitness for a particular purpose, or non-infringement of intellectual property or other violation of rights. Further, Supply Crow does not warrant or make any representations concerning the accuracy, likely results, or reliability of the use of the materials on its Internet web site or otherwise relating to such materials or on any sites linked to this site. </li> </ol> <h3> 4. Limitations </h3> <p> - In no event shall SupplyApp or its suppliers be liable for any damages (including, without limitation, damages for loss of data or profit, or due to business interruption,) arising out of the use or inability to use the materials on SupplyApp's Internet site, even if SupplyApp or a SupplyApp authorized representative has been notified orally or in writing of the possibility of such damage. Because some jurisdictions do not allow limitations on implied warranties, or limitations of liability for consequential or incidental damages, these limitations may not apply to you. + In no event shall Supply Crow or its suppliers be liable for any damages (including, without limitation, damages for loss of data or profit, or due to business interruption,) arising out of the use or inability to use the materials on Supply Crow's Internet site, even if Supply Crow or a Supply Crow authorized representative has been notified orally or in writing of the possibility of such damage. Because some jurisdictions do not allow limitations on implied warranties, or limitations of liability for consequential or incidental damages, these limitations may not apply to you. </p> <h3> 5. Revisions and Errata </h3> <p> - The materials appearing on SupplyApp's web site could include technical, typographical, or photographic errors. SupplyApp does not warrant that any of the materials on its web site are accurate, complete, or current. SupplyApp may make changes to the materials contained on its web site at any time without notice. SupplyApp does not, however, make any commitment to update the materials. + The materials appearing on Supply Crow's web site could include technical, typographical, or photographic errors. Supply Crow does not warrant that any of the materials on its web site are accurate, complete, or current. Supply Crow may make changes to the materials contained on its web site at any time without notice. Supply Crow does not, however, make any commitment to update the materials. </p> <h3> 6. Links </h3> <p> - SupplyApp has not reviewed all of the sites linked to its Internet web site and is not responsible for the contents of any such linked site. The inclusion of any link does not imply endorsement by SupplyApp of the site. Use of any such linked web site is at the user's own risk. + Supply Crow has not reviewed all of the sites linked to its Internet web site and is not responsible for the contents of any such linked site. The inclusion of any link does not imply endorsement by Supply Crow of the site. Use of any such linked web site is at the user's own risk. </p> <h3> 7. Site Terms of Use Modifications </h3> <p> - SupplyApp may revise these terms of use for its web site at any time without notice. By using this web site you are agreeing to be bound by the then current version of these Terms and Conditions of Use. + Supply Crow may revise these terms of use for its web site at any time without notice. By using this web site you are agreeing to be bound by the then current version of these Terms and Conditions of Use. </p> <h3> 8. Governing Law </h3> <p> - Any claim relating to SupplyApp's web site shall be governed by the laws of the State of Alberta without regard to its conflict of law provisions. + Any claim relating to Supply Crow's web site shall be governed by the laws of the State of Alberta without regard to its conflict of law provisions. </p> <p> General Terms and Conditions applicable to Use of a Web Site. diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 6b94a04..e0565d8 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -3,7 +3,7 @@ <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title><%= content_for?(:title) ? yield(:title) : "Strong Lifters" %></title> + <title><%= content_for?(:title) ? "Strong Lifters | #{yield(:title)}" : "Strong Lifters" %></title> <%= stylesheet_link_tag "application" %> <%= javascript_include_tag "vendor/modernizr" %> <%= csrf_meta_tags %> @@ -21,11 +21,10 @@ <ul class="title-area"> <!-- Title Area --> <li class="name"> - <h1> - <a href="#"> - Supply - </a> - </h1> + <svg viewBox="0 0 82.515 266.693"> + <use xlink:href="<%= asset_path "sprite.svg#feather" %>"></use> + </svg> + <h1><%= link_to "Supply Crow", dashboard_path %></h1> </li> <li class="toggle-topbar menu-icon"><a href="#"><span>menu</span></a></li> </ul> @@ -84,120 +83,7 @@ <!-- End Navigation --> - <div class="row"> - - <!-- Side Bar --> - - <div class="large-4 small-12 columns"> - - <img src="http://placehold.it/500x500&text=Logo"> - - <div class="hide-for-small panel"> - <h3>Header</h3> - <h5 class="subheader">Risus ligula, aliquam nec fermentum vitae, sollicitudin eget urna. Donec dignissim nibh fermentum odio ornare sagittis. - </h5> - </div> - - <a href="#"> - <div class="panel callout radius"> - <h6>99Â items in your cart</h6> - </div> - </a> - - </div> - - <!-- End Side Bar --> - - - <!-- Thumbnails --> - - <div class="large-8 columns"> - <div class="row"> - - <div class="large-4 small-6 columns"> - <img src="http://placehold.it/1000x1000&text=Thumbnail"> - - <div class="panel"> - <h5>Item Name</h5> - <h6 class="subheader">$000.00</h6> - </div> - </div> - - <div class="large-4 small-6 columns"> - <img src="http://placehold.it/500x500&text=Thumbnail"> - - <div class="panel"> - <h5>Item Name</h5> - <h6 class="subheader">$000.00</h6> - </div> - </div> - - <div class="large-4 small-6 columns"> - <img src="http://placehold.it/500x500&text=Thumbnail"> - - <div class="panel"> - <h5>Item Name</h5> - <h6 class="subheader">$000.00</h6> - </div> - </div> - - <div class="large-4 small-6 columns"> - <img src="http://placehold.it/500x500&text=Thumbnail"> - - <div class="panel"> - <h5>Item Name</h5> - <h6 class="subheader">$000.00</h6> - </div> - </div> - - <div class="large-4 small-6 columns"> - <img src="http://placehold.it/500x500&text=Thumbnail"> - - <div class="panel"> - <h5>Item Name</h5> - <h6 class="subheader">$000.00</h6> - </div> - </div> - - <div class="large-4 small-6 columns"> - <img src="http://placehold.it/500x500&text=Thumbnail"> - - <div class="panel"> - <h5>Item Name</h5> - <h6 class="subheader">$000.00</h6> - </div> - </div> - </div> - - <!-- End Thumbnails --> - - - <!-- Managed By --> - <div class="row"> - <div class="large-12 columns"> - <div class="panel"> - <div class="row"> - - <div class="large-2 small-6 columns"> - <img src="http://placehold.it/300x300&text=Site Owner"> - </div> - - <div class="large-10 small-6 columns"> - <strong>This Site Is Managed By<hr/></strong> - - Risus ligula, aliquam nec fermentum vitae, sollicitudin eget urna. Donec dignissim nibh fermentum odio ornare sagittis - </div> - - </div> - </div> - </div> - - <!-- End Managed By --> - - </div> - </div> - </div> - + <%= yield %> <!-- Footer --> @@ -227,5 +113,8 @@ </div> </div> <%= javascript_include_tag "application" %> + <script type="text/javascript" charset="utf-8"> + $(function(){ $(document).foundation(); }); + </script> </body> </html> diff --git a/app/views/layouts/public.html.erb b/app/views/layouts/public.html.erb index 66e3964..0d08d7a 100644 --- a/app/views/layouts/public.html.erb +++ b/app/views/layouts/public.html.erb @@ -4,13 +4,23 @@ <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title><%= content_for?(:title) ? yield(:title) : "Strong Lifters" %></title> - <%= stylesheet_link_tag "application" %> + <%= stylesheet_link_tag "application" %> <%= javascript_include_tag "vendor/modernizr" %> <%= csrf_meta_tags %> </head> <body> <%= render partial: 'layouts/flash' %> + <header> + <div class="row"> + <div class="small-12 columns text-center"> + <h1>Supply <span class="svg-container"><%= image_tag "sprite.svg#feather", alt: "Crow feather", class: "feather" %></span>Crow</h1> + </div> + </div> + </header> <%= yield %> <%= javascript_include_tag "application" %> + <script type="text/javascript" charset="utf-8"> + $(function(){ $(document).foundation(); }); + </script> </body> </html> diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 4402ddc..9139f6a 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -15,4 +15,4 @@ <%= link_to t('.register_link'), new_registration_path, class: "button secondary bare" %> </div> <!-- /.small-12 --> <% end %> -</div> <!-- /.row -->
\ No newline at end of file +</div> <!-- /.row --> diff --git a/app/views/user_mailer/registration_email.html.erb b/app/views/user_mailer/registration_email.html.erb index 437f8c0..464ce50 100644 --- a/app/views/user_mailer/registration_email.html.erb +++ b/app/views/user_mailer/registration_email.html.erb @@ -1,2 +1,2 @@ <p><%= "Hi, #{@username}." %></p> -<p>The Supply Team</p> +<p>The Supply Crow Team</p> diff --git a/app/views/user_mailer/registration_email.text.erb b/app/views/user_mailer/registration_email.text.erb index c3b90f7..7f64ab5 100644 --- a/app/views/user_mailer/registration_email.text.erb +++ b/app/views/user_mailer/registration_email.text.erb @@ -1,3 +1,3 @@ <%= "Hi, #{@username}." %> -The Supply Team +The Supply Crow Team diff --git a/bin/bundler b/bin/bundler new file mode 100755 index 0000000..72c62ec --- /dev/null +++ b/bin/bundler @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'bundler' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('bundler', 'bundler') diff --git a/bin/byebug b/bin/byebug new file mode 100755 index 0000000..168cef3 --- /dev/null +++ b/bin/byebug @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'byebug' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('byebug', 'byebug') diff --git a/bin/cdiff b/bin/cdiff new file mode 100755 index 0000000..066279d --- /dev/null +++ b/bin/cdiff @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'cdiff' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('term-ansicolor', 'cdiff') diff --git a/bin/colortab b/bin/colortab new file mode 100755 index 0000000..195df76 --- /dev/null +++ b/bin/colortab @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'colortab' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('term-ansicolor', 'colortab') diff --git a/bin/coveralls b/bin/coveralls new file mode 100755 index 0000000..5a8ac81 --- /dev/null +++ b/bin/coveralls @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'coveralls' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('coveralls', 'coveralls') diff --git a/bin/decolor b/bin/decolor new file mode 100755 index 0000000..214e8d1 --- /dev/null +++ b/bin/decolor @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'decolor' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('term-ansicolor', 'decolor') diff --git a/bin/dotenv b/bin/dotenv new file mode 100755 index 0000000..f6fc0f5 --- /dev/null +++ b/bin/dotenv @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'dotenv' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('dotenv', 'dotenv') diff --git a/bin/erubis b/bin/erubis new file mode 100755 index 0000000..2c7348b --- /dev/null +++ b/bin/erubis @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'erubis' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('erubis', 'erubis') diff --git a/bin/htmldiff b/bin/htmldiff new file mode 100755 index 0000000..c70e238 --- /dev/null +++ b/bin/htmldiff @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'htmldiff' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('diff-lcs', 'htmldiff') diff --git a/bin/i18n-tasks b/bin/i18n-tasks new file mode 100755 index 0000000..f4f2b2a --- /dev/null +++ b/bin/i18n-tasks @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'i18n-tasks' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('i18n-tasks', 'i18n-tasks') diff --git a/bin/ldiff b/bin/ldiff new file mode 100755 index 0000000..8e3524a --- /dev/null +++ b/bin/ldiff @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'ldiff' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('diff-lcs', 'ldiff') diff --git a/bin/nokogiri b/bin/nokogiri new file mode 100755 index 0000000..d55f84b --- /dev/null +++ b/bin/nokogiri @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'nokogiri' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('nokogiri', 'nokogiri') diff --git a/bin/puma b/bin/puma new file mode 100755 index 0000000..d24478b --- /dev/null +++ b/bin/puma @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'puma' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('puma', 'puma') diff --git a/bin/pumactl b/bin/pumactl new file mode 100755 index 0000000..f3f7b2b --- /dev/null +++ b/bin/pumactl @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'pumactl' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('puma', 'pumactl') diff --git a/bin/rackup b/bin/rackup new file mode 100755 index 0000000..8cc9953 --- /dev/null +++ b/bin/rackup @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'rackup' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rack', 'rackup') @@ -1,8 +1,16 @@ #!/usr/bin/env ruby -begin - load File.expand_path("../spring", __FILE__) -rescue LoadError -end -APP_PATH = File.expand_path('../../config/application', __FILE__) -require_relative '../config/boot' -require 'rails/commands' +# +# This file was generated by Bundler. +# +# The application 'rails' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('railties', 'rails') @@ -1,8 +1,16 @@ #!/usr/bin/env ruby -begin - load File.expand_path("../spring", __FILE__) -rescue LoadError -end -require_relative '../config/boot' -require 'rake' -Rake.application.run +# +# This file was generated by Bundler. +# +# The application 'rake' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rake', 'rake') diff --git a/bin/rdoc b/bin/rdoc new file mode 100755 index 0000000..f57260f --- /dev/null +++ b/bin/rdoc @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'rdoc' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rdoc', 'rdoc') diff --git a/bin/restclient b/bin/restclient new file mode 100755 index 0000000..4d7bdcf --- /dev/null +++ b/bin/restclient @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'restclient' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rest-client', 'restclient') @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'ri' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rdoc', 'ri') diff --git a/bin/rspec.orig b/bin/rspec.orig new file mode 100755 index 0000000..c5cbea0 --- /dev/null +++ b/bin/rspec.orig @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby +<<<<<<< HEAD +======= +begin + load File.expand_path("../spring", __FILE__) +rescue LoadError +end +>>>>>>> 6bc4fbcae691a5118c9a792f9b8a241031c000ef +# +# This file was generated by Bundler. +# +# The application 'rspec' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rspec-core', 'rspec') diff --git a/bin/sass b/bin/sass new file mode 100755 index 0000000..d65bb10 --- /dev/null +++ b/bin/sass @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'sass' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('sass', 'sass') diff --git a/bin/sass-convert b/bin/sass-convert new file mode 100755 index 0000000..ddde743 --- /dev/null +++ b/bin/sass-convert @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'sass-convert' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('sass', 'sass-convert') diff --git a/bin/scss b/bin/scss new file mode 100755 index 0000000..9f5e435 --- /dev/null +++ b/bin/scss @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'scss' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('sass', 'scss') diff --git a/bin/sdoc b/bin/sdoc new file mode 100755 index 0000000..9da297e --- /dev/null +++ b/bin/sdoc @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'sdoc' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('sdoc', 'sdoc') diff --git a/bin/sdoc-merge b/bin/sdoc-merge new file mode 100755 index 0000000..e29a7d9 --- /dev/null +++ b/bin/sdoc-merge @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'sdoc-merge' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('sdoc', 'sdoc-merge') @@ -1,29 +1,16 @@ #!/usr/bin/env ruby -require 'pathname' - -# path to your application root. -APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) - -Dir.chdir APP_ROOT do - # This script is a starting point to setup your application. - # Add necessary setup steps to this file: +# +# This file was generated by Bundler. +# +# The application 'setup' is installed as part of a gem, and +# this file is here to facilitate running it. +# - puts "== Installing dependencies ==" - system "gem install bundler --conservative" - system "bundle check || bundle install" - - puts "\n== Copying sample files ==" - unless File.exist?("config/database.yml") - system "cp config/database.yml.example config/database.yml" - end - - puts "\n== Preparing database ==" - system "bin/rake db:setup" +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) - puts "\n== Removing old logs and tempfiles ==" - system "rm -f log/*" - system "rm -rf tmp/cache" +require 'rubygems' +require 'bundler/setup' - puts "\n== Restarting application server ==" - system "touch tmp/restart.txt" -end +load Gem.bin_path('factory_girl_rails', 'setup') @@ -1,18 +1,16 @@ #!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'spring' is installed as part of a gem, and +# this file is here to facilitate running it. +# -# This file loads spring without using Bundler, in order to be fast -# It gets overwritten when you run the `spring binstub` command +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) -unless defined?(Spring) - require "rubygems" - require "bundler" +require 'rubygems' +require 'bundler/setup' - if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m) - ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR) - ENV["GEM_HOME"] = "" - Gem.paths = ENV - - gem "spring", match[1] - require "spring/binstub" - end -end +load Gem.bin_path('spring', 'spring') diff --git a/bin/sprockets b/bin/sprockets new file mode 100755 index 0000000..09a1ad1 --- /dev/null +++ b/bin/sprockets @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'sprockets' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('sprockets', 'sprockets') diff --git a/bin/teaspoon b/bin/teaspoon new file mode 100755 index 0000000..9a2b3e9 --- /dev/null +++ b/bin/teaspoon @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'teaspoon' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('teaspoon', 'teaspoon') diff --git a/bin/term_display b/bin/term_display new file mode 100755 index 0000000..d65c316 --- /dev/null +++ b/bin/term_display @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'term_display' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('term-ansicolor', 'term_display') diff --git a/bin/term_mandel b/bin/term_mandel new file mode 100755 index 0000000..c7dd35e --- /dev/null +++ b/bin/term_mandel @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'term_mandel' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('term-ansicolor', 'term_mandel') diff --git a/bin/thor b/bin/thor new file mode 100755 index 0000000..8421e00 --- /dev/null +++ b/bin/thor @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'thor' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('thor', 'thor') diff --git a/bin/tilt b/bin/tilt new file mode 100755 index 0000000..09fe73e --- /dev/null +++ b/bin/tilt @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'tilt' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('tilt', 'tilt') diff --git a/config/environments/development.rb b/config/environments/development.rb index 68871b9..2fd6f2a 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -26,7 +26,7 @@ Rails.application.configure do # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. - config.assets.debug = true + config.assets.debug = false # Asset digests allow you to set far-future HTTP expiration dates on all assets, # yet still be able to expire them through the digest params. diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 01ef3e6..b8c29ca 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -9,3 +9,4 @@ Rails.application.config.assets.version = '1.0' # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # Rails.application.config.assets.precompile += %w( search.js ) +Rails.application.config.assets.precompile << /\.(?:svg|eot|woff|ttf)\z/ diff --git a/config/locales/en.yml b/config/locales/en.yml index 0912f85..4fe05cf 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -20,6 +20,23 @@ # available at http://guides.rubyonrails.org/i18n.html. en: + items: + index: + item_name: 'Item name' + new_item_button: 'Create item' + form: + name: 'Name' + description: 'Description' + serial_number: 'Serial Number' + purchase_price: 'Purchase Price' + purchase_date: 'Purchase date' + purchased_at: 'Purchase date' + create_button: 'Create item' + show: + delete_button: 'Delete' + delete_confirm: 'Confirm' + cancel_button: 'Cancel' + edit_button: 'Edit' registrations: new: username: "Username" diff --git a/config/routes.rb b/config/routes.rb index ff2c92d..9fa3218 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,8 @@ Rails.application.routes.draw do - root 'sessions#new' + root "sessions#new" resources :sessions, only: [:new, :create, :destroy] resources :registrations, only: [:new, :create] - get '/' => 'sessions#new', as: :dashboard + resources :items + get "/dashboard" => "items#index", as: :dashboard get "/terms" => "static_pages#terms" end diff --git a/db/migrate/20150228162534_create_items.rb b/db/migrate/20150228162534_create_items.rb new file mode 100644 index 0000000..59ce71b --- /dev/null +++ b/db/migrate/20150228162534_create_items.rb @@ -0,0 +1,15 @@ +class CreateItems < ActiveRecord::Migration + def change + create_table :items, id: :uuid do |t| + t.uuid :user_id, null: false + t.string :name + t.text :description + t.string :serial_number + t.decimal :purchase_price + t.datetime :purchased_at + + t.timestamps null: false + end + add_index :items, :user_id + end +end diff --git a/db/schema.rb b/db/schema.rb index f0d933e..08cb78a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,12 +11,25 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150124163233) do +ActiveRecord::Schema.define(version: 20150228162534) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" enable_extension "uuid-ossp" + create_table "items", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t| + t.uuid "user_id", null: false + t.string "name" + t.text "description" + t.string "serial_number" + t.decimal "purchase_price" + t.datetime "purchased_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "items", ["user_id"], name: "index_items_on_user_id", using: :btree + create_table "users", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t| t.string "username", null: false t.string "email", null: false diff --git a/public/favicon.ico b/public/favicon.ico Binary files differindex e69de29..4dc2f9b 100644 --- a/public/favicon.ico +++ b/public/favicon.ico diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb new file mode 100644 index 0000000..9dbd5aa --- /dev/null +++ b/spec/controllers/application_controller_spec.rb @@ -0,0 +1,26 @@ +require "rails_helper" + +describe ApplicationController, type: :controller do + controller do + def index + render text: "WHAT?" + end + end + + context "when not logged in" do + it "redirects you to the login page" do + get :index + expect(response).to redirect_to(new_session_path) + end + end + + context "when logged in" do + let(:user) { create(:user) } + + it "allows the action to do it's thing" do + auth_user(user) + get :index + expect(response.body).to eql("WHAT?") + end + end +end diff --git a/spec/controllers/items_controller_spec.rb b/spec/controllers/items_controller_spec.rb new file mode 100644 index 0000000..7ffff17 --- /dev/null +++ b/spec/controllers/items_controller_spec.rb @@ -0,0 +1,159 @@ +require "rails_helper" + +RSpec.describe ItemsController, type: :controller do + context "when logged in" do + let(:user) { create(:user) } + + before :each do + auth_user(user) + end + + describe "#index" do + let(:other_user) { create(:user) } + let!(:my_item) { create(:item, user: user) } + let!(:their_item) { create(:item, user: other_user) } + + it "loads all your items" do + get :index + expect(assigns(:items)).to match_array([my_item]) + end + end + + describe "#show" do + let(:item) { create(:item, user: user) } + let(:other_user) { create(:user) } + let(:other_guys_item) { create(:item, user: other_user) } + + it "loads your item" do + get :show, id: item.id + expect(assigns(:item)).to eql(item) + end + + it "does not load other peoples items" do + get :show, id: other_guys_item.id + expect(response.status).to eql(404) + end + end + + describe "#new" do + it "loads up an empty item" do + get :new + expect(assigns(:item)).to_not be_nil + end + + it "loads up the params for a new item" do + get :new, item: { name: "hammer" } + expect(assigns(:item).name).to eql("hammer") + end + end + + describe "#edit" do + let(:my_item) { create(:item, user: user) } + + it "loads the item to edit" do + get :edit, id: my_item.id + expect(assigns(:item)).to eql(my_item) + end + + context "when attempting to edit someone elses item" do + let(:other_item) { create(:item, user: other_user) } + let(:other_user) { create(:user) } + + it "returns a 404" do + get :edit, id: other_item.id + + expect(assigns(:item)).to be_nil + expect(response.status).to eql(404) + end + end + end + + describe "#create" do + let(:exclusions) { ["id", "user_id"] } + let(:item_params) do + build(:item).attributes.reject { |key, _| exclusions.include?(key) } + end + + it "creates the new item" do + post :create, item: item_params + + expect(Item.count).to eql(1) + item = Item.first + expect(item.user).to eql(user) + expect(item.name).to eql(item_params["name"]) + expect(item.description).to eql(item_params["description"]) + expect(item.serial_number).to eql(item_params["serial_number"]) + expect(item.purchase_price).to eql(item_params["purchase_price"]) + expect(item.purchased_at.to_i).to eql(item_params["purchased_at"].to_i) + end + + it "redirects back to the dashboard" do + put :create, item: item_params + + expect(response).to redirect_to(dashboard_path) + end + + context "when some of the fields are invalid" do + it "displays the errors" do + post :create, item: { name: "" } + expect(flash[:warning]).to_not be_empty + end + end + end + + describe "#update" do + let(:my_item) { create(:item, user: user) } + let(:item_params) { build(:item).attributes } + + it "updates the item" do + patch :update, id: my_item.id, item: item_params + + my_item.reload + expect(my_item.user).to eql(user) + expect(my_item.name).to eql(item_params["name"]) + expect(my_item.description).to eql(item_params["description"]) + expect(my_item.serial_number).to eql(item_params["serial_number"]) + expect(my_item.purchase_price).to eql(item_params["purchase_price"]) + end + + it "redirects to the dashboard" do + patch :update, id: my_item.id, item: item_params + + expect(response).to redirect_to(dashboard_path) + end + end + + describe "#destroy" do + let(:my_item) { create(:item, user: user) } + let(:other_item) { create(:item, user: other_user) } + let(:other_user) { create(:user) } + + it "deletes the item" do + delete :destroy, id: my_item.id + + expect(Item.count).to eql(0) + end + + it "cannot delete another persons item" do + delete :destroy, id: other_item.id + + expect(response.status).to eql(404) + end + + it "redirects to the dashboard" do + delete :destroy, id: my_item.id + + expect(response).to redirect_to(dashboard_path) + end + end + end + + context "when not logged in" do + describe "#index" do + it "redirects to the login page" do + get :index + expect(response).to redirect_to(new_session_path) + end + end + end +end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index dc59e08..2f8a09f 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -1,52 +1,48 @@ require "rails_helper" describe SessionsController do - describe "#create" do - let(:user) { create(:user, password: "password") } - + context "when credentials are correct" do - it "logs you in with email" do post :create, { user: { username: user.email, password: "password" } } expect(session[:user_id]).to eql(user.id) end - + it "logs you in with username" do post :create, { user: { username: user.username, password: "password" } } expect(session[:user_id]).to eql(user.id) end - + + it "redirects to the dashboard" do + post :create, { user: { username: user.username, password: "password" } } + expect(response).to redirect_to(dashboard_path) + end end - + context "when credentials are incorrect" do - it "displays errors" do post :create, { user: { username: user.username, password: "wrong" } } expect(flash[:warning]).to_not be_empty end - + it "redirects to the login page" do post :create, { user: { username: user.username, password: "wrong" } } expect(response).to redirect_to(new_session_path) end - end end - + describe "#destroy" do context "when logged in" do - let(:user) { create(:user) } - + it "logs you out" do session[:user_id] = user.id delete :destroy, id: user.id expect(session[:user_id]).to be_nil end - end end - -end
\ No newline at end of file +end diff --git a/spec/factories/items.rb b/spec/factories/items.rb new file mode 100644 index 0000000..be92fdc --- /dev/null +++ b/spec/factories/items.rb @@ -0,0 +1,9 @@ +FactoryGirl.define do + factory :item do + name FFaker::Name.name + description FFaker::HipsterIpsum.words(50) + serial_number SecureRandom.uuid + purchase_price { (rand(1_000) + rand).round(2) } + purchased_at DateTime.now + end +end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index bc28377..c0a9b1e 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,7 +1,7 @@ FactoryGirl.define do factory :user do - username Faker::Internet.user_name - email Faker::Internet.email + username { FFaker::Internet.user_name } + email { FFaker::Internet.email } password "password" password_confirmation "password" terms_and_conditions "1" diff --git a/spec/features/items_spec.rb b/spec/features/items_spec.rb new file mode 100644 index 0000000..823f2e8 --- /dev/null +++ b/spec/features/items_spec.rb @@ -0,0 +1,53 @@ +require "rails_helper" + +feature "items", type: :feature, js: true do + describe "GET /items" do + subject { ItemsPage.new } + let(:user) { create(:user) } + let!(:item) { create(:item, user: user) } + + context "when logged in" do + before :each do + subject.login_with(user.username, "password") + subject.visit_page + end + + it "loads a list of items" do + expect(page).to have_content(item.name) + end + + it "can start to add a new item" do + subject.add_item("new item") + expect(page).to have_selector("input[value='new item']") + end + end + + context "not logged in" do + it 'redirects you to the login page' do + subject.visit_page + expect(page.current_path).to eql(new_session_path) + end + end + end + + describe "POST /items" do + subject { NewItemPage.new } + let(:user) { create(:user) } + + before :each do + subject.login_with(user.username, "password") + subject.visit_page + end + + it "creates a new item" do + subject.create_item( + name: "hammer", + description: "for hammering things", + serial_number: "123456", + purchase_price: "1.99", + purchased_at: "2015-01-01", + ) + expect(subject).to have_content("hammer") + end + end +end diff --git a/spec/features/registrations_spec.rb b/spec/features/registrations_spec.rb index ed00835..94c7e03 100644 --- a/spec/features/registrations_spec.rb +++ b/spec/features/registrations_spec.rb @@ -1,6 +1,6 @@ require "rails_helper" -feature "Registrations", type: :feature do +feature "Registrations", type: :feature, js: true do subject { NewRegistrationPage.new } before :each do diff --git a/spec/features/sessions_spec.rb b/spec/features/sessions_spec.rb index bb8b309..6866433 100644 --- a/spec/features/sessions_spec.rb +++ b/spec/features/sessions_spec.rb @@ -1,8 +1,9 @@ require "rails_helper" -describe "Sessions" do +feature "Sessions", type: :feature do subject { LoginPage.new } - let(:user){ create(:user,:password => "password") } + let(:user) { create(:user, password: "password") } + context "credentials are correct" do it "takes you to your dashboard" do subject.visit_page @@ -10,4 +11,4 @@ describe "Sessions" do expect(current_path).to eql(dashboard_path) end end -end
\ No newline at end of file +end diff --git a/spec/javascripts/calculator_spec.js.coffee b/spec/javascripts/calculator_spec.js.coffee new file mode 100644 index 0000000..0046630 --- /dev/null +++ b/spec/javascripts/calculator_spec.js.coffee @@ -0,0 +1,4 @@ +#= require models/calculator +describe "Calculator", -> + it "adds two digits", -> + expect(new SupplyCrow.Calculator().add(2, 2)).toBe(4) diff --git a/spec/javascripts/spec_helper.coffee b/spec/javascripts/spec_helper.coffee new file mode 100644 index 0000000..23866f2 --- /dev/null +++ b/spec/javascripts/spec_helper.coffee @@ -0,0 +1,31 @@ +# Teaspoon includes some support files, but you can use anything from your own support path too. +# require support/jasmine-jquery-1.7.0 +# require support/jasmine-jquery-2.0.0 +# require support/sinon +# require support/your-support-file +# +# PhantomJS (Teaspoons default driver) doesn't have support for Function.prototype.bind, which has caused confusion. +# Use this polyfill to avoid the confusion. +#= require support/bind-poly +# +# Deferring execution +# If you're using CommonJS, RequireJS or some other asynchronous library you can defer execution. Call +# Teaspoon.execute() after everything has been loaded. Simple example of a timeout: +# +# Teaspoon.defer = true +# setTimeout(Teaspoon.execute, 1000) +# +# Matching files +# By default Teaspoon will look for files that match _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your +# spec path and it'll be included in the default suite automatically. If you want to customize suites, check out the +# configuration in config/initializers/teaspoon.rb +# +# Manifest +# If you'd rather require your spec files manually (to control order for instance) you can disable the suite matcher in +# the configuration and use this file as a manifest. +# +# For more information: http://github.com/modeset/teaspoon +# +# You can require your own javascript files here. By default this will include everything in application, however you +# may get better load performance if you require the specific files that are being used in the spec that tests them. +#= require application diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 95a9a58..8958c7f 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -5,7 +5,7 @@ RSpec.describe UserMailer, type: :mailer do let(:user) { double User, username: "blah", email:"blah@example.com" } let(:mail) { UserMailer.registration_email(user) } it "renders the subject" do - expect(mail.subject).to eql("Welcome to Supply.") + expect(mail.subject).to eql("Welcome to Supply Crow.") end it "renders the recipient email" do expect(mail.to).to eql([user.email]) diff --git a/spec/models/item_spec.rb b/spec/models/item_spec.rb new file mode 100644 index 0000000..9750621 --- /dev/null +++ b/spec/models/item_spec.rb @@ -0,0 +1,19 @@ +require "rails_helper" + +RSpec.describe Item, type: :model do + describe "validations" do + let(:user) { create(:user) } + + it "validates the presence of a user" do + item = build(:item, user: nil) + expect(item).to_not be_valid + expect(item.errors[:user]).to_not be_empty + end + + it "validates the presence of a name" do + item = build(:item, user: user, name: nil) + expect(item).to_not be_valid + expect(item.errors[:name]).to_not be_empty + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 68e5160..029bbbb 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,10 +1,10 @@ -# This file is copied to spec/ when you run 'rails generate rspec:install' -ENV["RAILS_ENV"] ||= 'test' -require 'coveralls' -Coveralls.wear!('rails') -require 'spec_helper' +# This file is copied to spec/ when you run "rails generate rspec:install" +ENV["RAILS_ENV"] ||= "test" +require "coveralls" +Coveralls.wear!("rails") +require "spec_helper" require File.expand_path("../../config/environment", __FILE__) -require 'rspec/rails' +require "rspec/rails" require "capybara/poltergeist" # Add additional requires below this line. Rails is not loaded until this point! @@ -29,11 +29,12 @@ ActiveRecord::Migration.maintain_test_schema! Capybara.javascript_driver = :poltergeist RSpec.configure do |config| - # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + # Remove this line if you"re not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" config.include FactoryGirl::Syntax::Methods + config.include HttpAuthentication - # If you're not using ActiveRecord, or you'd prefer not to run each of your + # If you"re not using ActiveRecord, or you"d prefer not to run each of your # examples within a transaction, remove the following line or assign false # instead of true. config.use_transactional_fixtures = false @@ -62,6 +63,7 @@ RSpec.configure do |config| config.before(:each, js: true) do DatabaseCleaner.strategy = :truncation + page.driver.browser.url_blacklist = ["http://fonts.googleapis.com"] end config.before(:each) do diff --git a/spec/routing/dashboard_routing_spec.rb b/spec/routing/dashboard_routing_spec.rb new file mode 100644 index 0000000..bf2eae5 --- /dev/null +++ b/spec/routing/dashboard_routing_spec.rb @@ -0,0 +1,7 @@ +require "rails_helper" + +RSpec.describe "/dashboard", type: :routing do + it "routes to the items listing" do + expect(get: "/dashboard").to route_to("items#index") + end +end diff --git a/spec/routing/items_routing_spec.rb b/spec/routing/items_routing_spec.rb new file mode 100644 index 0000000..eb6d302 --- /dev/null +++ b/spec/routing/items_routing_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe ItemsController, type: :routing do + describe "routing" do + it "routes to #index" do + expect(get: "/items").to route_to("items#index") + end + + it "routes to #new" do + expect(get: "/items/new").to route_to("items#new") + end + + it "routes to #show" do + expect(get: "/items/1").to route_to("items#show", id: "1") + end + + it "routes to #edit" do + expect(get: "/items/1/edit").to route_to("items#edit", id: "1") + end + + it "routes to #create" do + expect(post: "/items").to route_to("items#create") + end + + it "routes to #update" do + expect(put: "/items/1").to route_to("items#update", id: "1") + end + + it "routes to #destroy" do + expect(delete: "/items/1").to route_to("items#destroy", id: "1") + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 275ba49..4646308 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -38,9 +38,8 @@ RSpec.configure do |config| mocks.verify_partial_doubles = true end -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. # These two settings work together to allow you to limit a spec run # to individual examples or groups you care about by tagging them with # `:focus` metadata. When nothing is tagged with `:focus`, all examples @@ -53,7 +52,7 @@ RSpec.configure do |config| # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching - config.disable_monkey_patching! + # config.disable_monkey_patching! # Many RSpec users commonly either run the entire suite or an individual # file, and it's useful to allow more verbose output when running an @@ -81,5 +80,4 @@ RSpec.configure do |config| # test failures related to randomization by passing the same `--seed` value # as the one that triggered the failure. Kernel.srand config.seed -=end end diff --git a/spec/support/http_authentication.rb b/spec/support/http_authentication.rb new file mode 100644 index 0000000..ff10499 --- /dev/null +++ b/spec/support/http_authentication.rb @@ -0,0 +1,5 @@ +module HttpAuthentication + def auth_user(user) + session[:user_id] = user.id + end +end diff --git a/spec/support/page_model.rb b/spec/support/page_model.rb index c5ce601..45c45b3 100644 --- a/spec/support/page_model.rb +++ b/spec/support/page_model.rb @@ -15,4 +15,11 @@ class PageModel def on_page? current_path == page_path end + + def login_with(username, password) + LoginPage.new.tap do |login_page| + login_page.visit_page + login_page.login_with(username, password) + end + end end diff --git a/spec/support/pages/items_page.rb b/spec/support/pages/items_page.rb new file mode 100644 index 0000000..88865b1 --- /dev/null +++ b/spec/support/pages/items_page.rb @@ -0,0 +1,36 @@ +require_relative "../page_model.rb" + +class ItemsPage < PageModel + def initialize + super dashboard_path + end + + def add_item(item_name) + within "#new_item" do + fill_in I18n.translate("items.index.item_name"), with: item_name + click_button I18n.translate("items.index.new_item_button") + end + end +end + +class NewItemPage < PageModel + def initialize + super new_item_path + end + + def create_item(name:, + description: '', + serial_number: '', + purchase_price: '', + purchased_at: '' + ) + within "#new_item" do + fill_in I18n.translate("items.form.name"), with: name + fill_in I18n.translate("items.form.description"), with: description + fill_in I18n.translate("items.form.serial_number"), with: serial_number + fill_in I18n.translate("items.form.purchase_price"), with: purchase_price + fill_in I18n.translate("items.form.purchased_at"), with: purchased_at + click_button I18n.translate("items.form.create_button") + end + end +end diff --git a/spec/support/pages/login_page.rb b/spec/support/pages/login_page.rb index 29c972b..1ab9cca 100644 --- a/spec/support/pages/login_page.rb +++ b/spec/support/pages/login_page.rb @@ -1,11 +1,10 @@ require_relative "../page_model.rb" class LoginPage < PageModel - def initialize super new_session_path end - + def login_with(username, password) within("#new_user") do fill_in I18n.translate("sessions.new.username"), :with => username @@ -13,5 +12,4 @@ class LoginPage < PageModel click_button I18n.translate("sessions.new.login_button") end end - -end
\ No newline at end of file +end diff --git a/spec/support/pages/new_registration_page.rb b/spec/support/pages/new_registration_page.rb index bb6988e..aa51692 100644 --- a/spec/support/pages/new_registration_page.rb +++ b/spec/support/pages/new_registration_page.rb @@ -5,8 +5,8 @@ class NewRegistrationPage < PageModel super(new_registration_path) end - def register_with(username: Faker::Internet.user_name, - email: Faker::Internet.email, + def register_with(username: FFaker::Internet.user_name, + email: FFaker::Internet.email, password: "password", accept_terms: true) within "#new_user" do diff --git a/spec/teaspoon_env.rb b/spec/teaspoon_env.rb new file mode 100644 index 0000000..329d7d2 --- /dev/null +++ b/spec/teaspoon_env.rb @@ -0,0 +1,179 @@ +# Set RAILS_ROOT and load the environment if it's not already loaded. +unless defined?(Rails) + ENV["RAILS_ROOT"] = File.expand_path("../../", __FILE__) + require File.expand_path("../../config/environment", __FILE__) +end + +Teaspoon.configure do |config| + + # Determines where the Teaspoon routes will be mounted. Changing this to "/jasmine" would allow you to browse to + # `http://localhost:3000/jasmine` to run your tests. + #config.mount_at = "/teaspoon" + + # Specifies the root where Teaspoon will look for files. If you're testing an engine using a dummy application it can + # be useful to set this to your engines root (e.g. `Teaspoon::Engine.root`). + # Note: Defaults to `Rails.root` if nil. + #config.root = nil + + # Paths that will be appended to the Rails assets paths + # Note: Relative to `config.root`. + #config.asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets"] + + # Fixtures are rendered through a controller, which allows using HAML, RABL/JBuilder, etc. Files in these paths will + # be rendered as fixtures. + #config.fixture_paths = ["spec/javascripts/fixtures"] + + # SUITES + # + # You can modify the default suite configuration and create new suites here. Suites are isolated from one another. + # + # When defining a suite you can provide a name and a block. If the name is left blank, :default is assumed. You can + # omit various directives and the ones defined in the default suite will be used. + # + # To run a specific suite + # - in the browser: http://localhost/teaspoon/[suite_name] + # - with the rake task: rake teaspoon suite=[suite_name] + # - with the cli: teaspoon --suite=[suite_name] + config.suite do |suite| + + # Specify the framework you would like to use. This allows you to select versions, and will do some basic setup for + # you -- which you can override with the directives below. This should be specified first, as it can override other + # directives. + # Note: If no version is specified, the latest is assumed. + # + # Available: jasmine[1.3.1, 2.0.0], mocha[1.10.0, 1.17.1] qunit[1.12.0, 1.14.0] + suite.use_framework :jasmine, "1.3.1" + + # Specify a file matcher as a regular expression and all matching files will be loaded when the suite is run. These + # files need to be within an asset path. You can add asset paths using the `config.asset_paths`. + #suite.matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.coffee,coffee}" + + # This suites spec helper, which can require additional support files. This file is loaded before any of your test + # files are loaded. + #suite.helper = "spec_helper" + + # The core Teaspoon javascripts. It's recommended to include only the base files here, as you can require support + # libraries from your spec helper. + # Note: For CoffeeScript files use `"teaspoon/jasmine"` etc. + # + # Available: teaspoon-jasmine, teaspoon-mocha, teaspoon-qunit + #suite.javascripts = ["jasmine/1.3.1", "teaspoon-jasmine"] + + # You can include your own stylesheets if you want to change how Teaspoon looks. + # Note: Spec related CSS can and should be loaded using fixtures. + #suite.stylesheets = ["teaspoon"] + + # Partial to be rendered in the head tag of the runner. You can use the provided ones or define your own by creating + # a `_boot.html.erb` in your fixtures path, and adjust the config to `"/boot"` for instance. + # + # Available: boot, boot_require_js + #suite.boot_partial = "boot" + + # Partial to be rendered in the body tag of the runner. You can define your own to create a custom body structure. + #suite.body_partial = "body" + + # Assets to be ignored when generating coverage reports. Accepts an array of filenames or regular expressions. The + # default excludes assets from vendor, gems and support libraries.<br/><br/> + #suite.no_coverage = [%r{/lib/ruby/gems/}, %r{/vendor/assets/}, %r{/support/}, %r{/(.+)_helper.}] + + # Hooks allow you to use `Teaspoon.hook("fixtures")` before, after, or during your spec run. This will make a + # synchronous Ajax request to the server that will call all of the blocks you've defined for that hook name. + #suite.hook :fixtures, proc{ } + end + + # Example suite. Since we're just filtering to files already within the root test/javascripts, these files will also + # be run in the default suite -- but can be focused into a more specific suite. + #config.suite :targeted do |suite| + # suite.matcher = "test/javascripts/targeted/*_test.{js,js.coffee,coffee}" + #end + + # CONSOLE RUNNER SPECIFIC + # + # These configuration directives are applicable only when running via the rake task or command line interface. These + # directives can be overridden using the command line interface arguments or with ENV variables when using the rake + # task. + # + # Command Line Interface: + # teaspoon --driver=phantomjs --server-port=31337 --fail-fast=true --format=junit --suite=my_suite /spec/file_spec.js + # + # Rake: + # teaspoon DRIVER=phantomjs SERVER_PORT=31337 FAIL_FAST=true FORMATTERS=junit suite=my_suite + + # Specify which headless driver to use. Supports PhantomJS and Selenium Webdriver. + # + # Available: phantomjs, selenium + # PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS + # Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver + #config.driver = "phantomjs" + + # Specify additional options for the driver. + # + # PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS + # Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver + #config.driver_options = nil + + # Specify the timeout for the driver. Specs are expected to complete within this time frame or the run will be + # considered a failure. This is to avoid issues that can arise where tests stall. + #config.driver_timeout = 180 + + # Specify a server to use with Rack (e.g. thin, mongrel). If nil is provided Rack::Server is used. + #config.server = nil + + # Specify a port to run on a specific port, otherwise Teaspoon will use a random available port. + #config.server_port = nil + + # Timeout for starting the server in seconds. If your server is slow to start you may have to bump this, or you may + # want to lower this if you know it shouldn't take long to start. + #config.server_timeout = 20 + + # Force Teaspoon to fail immediately after a failing suite. Can be useful to make Teaspoon fail early if you have + # several suites, but in environments like CI this may not be desirable. + #config.fail_fast = true + + # Specify the formatters to use when outputting the results. + # Note: Output files can be specified by using `"junit>/path/to/output.xml"`. + # + # Available: dot, documentation, clean, json, junit, pride, snowday, swayze_or_oprah, tap, tap_y, teamcity + #config.formatters = ["dot"] + + # Specify if you want color output from the formatters. + #config.color = true + + # Teaspoon pipes all console[log/debug/error] to $stdout. This is useful to catch places where you've forgotten to + # remove them, but in verbose applications this may not be desirable. + #config.suppress_log = false + + # COVERAGE REPORTS / THRESHOLD ASSERTIONS + # + # Coverage reports requires Istanbul (https://github.com/gotwarlost/istanbul) to add instrumentation to your code and + # display coverage statistics. + # + # Coverage configurations are similar to suites. You can define several, and use different ones under different + # conditions. + # + # To run with a specific coverage configuration + # - with the rake task: rake teaspoon USE_COVERAGE=[coverage_name] + # - with the cli: teaspoon --coverage=[coverage_name] + + # Specify that you always want a coverage configuration to be used. + #config.use_coverage = nil + + config.coverage do |coverage| + # Which coverage reports Instanbul should generate. Correlates directly to what Istanbul supports. + # + # Available: text-summary, text, html, lcov, lcovonly, cobertura, teamcity + #coverage.reports = ["text-summary", "html"] + coverage.reports = ['text', 'html', 'lcov', 'cobertura'] + + # The path that the coverage should be written to - when there's an artifact to write to disk. + # Note: Relative to `config.root`. + #coverage.output_dir = "coverage" + + # Various thresholds requirements can be defined, and those thresholds will be checked at the end of a run. If any + # aren't met the run will fail with a message. Thresholds can be defined as a percentage (0-100), or nil. + coverage.statements = 80 + coverage.functions = 80 + coverage.branches = 80 + coverage.lines = 80 + end +end |
