diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..6e907a2
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,14 @@
+### v0.1.0
+* Integrate rspec
+* Add rake db:reset task
+* Upgrade rake to 10.1.0
+* Upgrade sinatra to 1.4.3
+* Upgrade sinatra-contrib to 1.4.1
+
+### v.0.1.1
+* Implement a basic class and spec to exercise it
+* Relocate misplaced comma set
+* Convert models/README to Markdown
+* Correct misusue of e.g.
+* Convert helpers/README to Markdown
+* Implement a "em" helper for reference; improve README
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..8747fba
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,30 @@
+source 'https://rubygems.org'
+ruby '2.0.0'
+
+# PostgreSQL driver
+gem 'pg'
+
+# Sinatra driver
+gem 'sinatra'
+gem 'sinatra-contrib'
+
+gem 'activesupport', '~>4.1'
+gem 'activerecord', '~>4.1'
+
+gem 'rake'
+
+gem 'shotgun'
+
+gem 'bcrypt'
+gem 'faker'
+
+group :test do
+ gem 'shoulda-matchers'
+ gem 'rack-test'
+ gem 'rspec'
+ gem 'capybara'
+end
+
+group :test, :development do
+ gem 'factory_girl'
+end
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..9c4574a
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,94 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activemodel (4.1.1)
+ activesupport (= 4.1.1)
+ builder (~> 3.1)
+ activerecord (4.1.1)
+ activemodel (= 4.1.1)
+ activesupport (= 4.1.1)
+ arel (~> 5.0.0)
+ activesupport (4.1.1)
+ i18n (~> 0.6, >= 0.6.9)
+ json (~> 1.7, >= 1.7.7)
+ minitest (~> 5.1)
+ thread_safe (~> 0.1)
+ tzinfo (~> 1.1)
+ arel (5.0.1.20140414130214)
+ backports (3.6.0)
+ bcrypt (3.1.10)
+ builder (3.2.2)
+ capybara (2.2.1)
+ mime-types (>= 1.16)
+ nokogiri (>= 1.3.3)
+ rack (>= 1.0.0)
+ rack-test (>= 0.5.4)
+ xpath (~> 2.0)
+ diff-lcs (1.2.5)
+ factory_girl (4.4.0)
+ activesupport (>= 3.0.0)
+ faker (1.3.0)
+ i18n (~> 0.5)
+ i18n (0.6.9)
+ json (1.8.1)
+ mime-types (2.3)
+ mini_portile (0.6.0)
+ minitest (5.3.4)
+ multi_json (1.10.1)
+ nokogiri (1.6.2.1)
+ mini_portile (= 0.6.0)
+ pg (0.17.1)
+ rack (1.5.2)
+ rack-protection (1.5.3)
+ rack
+ rack-test (0.6.2)
+ rack (>= 1.0)
+ rake (10.3.2)
+ rspec (2.14.1)
+ rspec-core (~> 2.14.0)
+ rspec-expectations (~> 2.14.0)
+ rspec-mocks (~> 2.14.0)
+ rspec-core (2.14.8)
+ rspec-expectations (2.14.5)
+ diff-lcs (>= 1.1.3, < 2.0)
+ rspec-mocks (2.14.6)
+ shotgun (0.9)
+ rack (>= 1.0)
+ shoulda-matchers (2.6.1)
+ activesupport (>= 3.0.0)
+ sinatra (1.4.5)
+ rack (~> 1.4)
+ rack-protection (~> 1.4)
+ tilt (~> 1.3, >= 1.3.4)
+ sinatra-contrib (1.4.2)
+ backports (>= 2.0)
+ multi_json
+ rack-protection
+ rack-test
+ sinatra (~> 1.4.0)
+ tilt (~> 1.3)
+ thread_safe (0.3.4)
+ tilt (1.4.1)
+ tzinfo (1.2.0)
+ thread_safe (~> 0.1)
+ xpath (2.0.0)
+ nokogiri (~> 1.3)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ activerecord (~> 4.1)
+ activesupport (~> 4.1)
+ bcrypt
+ capybara
+ factory_girl
+ faker
+ pg
+ rack-test
+ rake
+ rspec
+ shotgun
+ shoulda-matchers
+ sinatra
+ sinatra-contrib
diff --git a/README.md b/README.md
index 48cc4d4..11a2945 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,24 @@
-This repo should be used to hold your phase 2, week 1 passion project.
-see more about [portfolio challenges and passion projects here](../../../phase-2-guide/blob/sf/portfolio_challenges.md)
+
+### Quickstart
+
+1. `bundle install`
+2. `bundle exec shotgun config.ru`
+3. `bundle exec rake db:create`
+4. `bundle exec rake db:migrate`
+5. `bundle exec rake db:seed`
+6. [Local host page](http://localhost:9393/)
+
+These tasks might not need `bundle exec` prepended to it
+
+### A website for community sharing of Car Costs
+
+1. Website has authentication and authorizations with login and registration
+2. Website has a many to many relationship with Users, Prices and Cars.
+3. Website uses activerecord CRUD to create, read, update and delete prices.
+4. Website has validations and error handling.
+5. Website uses html and css.
+6. Website uses Sinatra for routing.
+
+
+## by Andrew Yan
\ No newline at end of file
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..a993c81
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,141 @@
+require 'rake'
+
+require ::File.expand_path('../config/environment', __FILE__)
+
+# Include all of ActiveSupport's core class extensions, e.g., String#camelize
+require 'active_support/core_ext'
+
+namespace :generate do
+ desc "Create an empty model in app/models, e.g., rake generate:model NAME=User"
+ task :model do
+ unless ENV.has_key?('NAME')
+ raise "Must specificy model name, e.g., rake generate:model NAME=User"
+ end
+
+ model_name = ENV['NAME'].camelize
+ model_filename = ENV['NAME'].underscore + '.rb'
+ model_path = APP_ROOT.join('app', 'models', model_filename)
+
+ if File.exist?(model_path)
+ raise "ERROR: Model file '#{model_path}' already exists"
+ end
+
+ puts "Creating #{model_path}"
+ File.open(model_path, 'w+') do |f|
+ f.write(<<-EOF.strip_heredoc)
+ class #{model_name} < ActiveRecord::Base
+ # Remember to create a migration!
+ end
+ EOF
+ end
+ end
+
+ desc "Create an empty migration in db/migrate, e.g., rake generate:migration NAME=create_tasks"
+ task :migration do
+ unless ENV.has_key?('NAME')
+ raise "Must specificy migration name, e.g., rake generate:migration NAME=create_tasks"
+ end
+
+ name = ENV['NAME'].camelize
+ filename = "%s_%s.rb" % [Time.now.strftime('%Y%m%d%H%M%S'), ENV['NAME'].underscore]
+ path = APP_ROOT.join('db', 'migrate', filename)
+
+ if File.exist?(path)
+ raise "ERROR: File '#{path}' already exists"
+ end
+
+ puts "Creating #{path}"
+ File.open(path, 'w+') do |f|
+ f.write(<<-EOF.strip_heredoc)
+ class #{name} < ActiveRecord::Migration
+ def change
+ end
+ end
+ EOF
+ end
+ end
+
+ desc "Create an empty model spec in spec, e.g., rake generate:spec NAME=user"
+ task :spec do
+ unless ENV.has_key?('NAME')
+ raise "Must specificy migration name, e.g., rake generate:spec NAME=user"
+ end
+
+ name = ENV['NAME'].camelize
+ filename = "%s_spec.rb" % ENV['NAME'].underscore
+ path = APP_ROOT.join('spec', filename)
+
+ if File.exist?(path)
+ raise "ERROR: File '#{path}' already exists"
+ end
+
+ puts "Creating #{path}"
+ File.open(path, 'w+') do |f|
+ f.write(<<-EOF.strip_heredoc)
+ require 'spec_helper'
+
+ describe #{name} do
+ pending "add some examples to (or delete) #{__FILE__}"
+ end
+ EOF
+ end
+ end
+
+end
+
+namespace :db do
+ desc "Drop, create, and migrate the database"
+ task :reset => [:drop, :create, :migrate]
+
+ desc "Create the databases at #{DB_NAME}"
+ task :create do
+ puts "Creating development and test databases if they don't exist..."
+ system("createdb #{APP_NAME}_development && createdb #{APP_NAME}_test")
+ end
+
+ desc "Drop the database at #{DB_NAME}"
+ task :drop do
+ puts "Dropping development and test databases..."
+ system("dropdb #{APP_NAME}_development && dropdb #{APP_NAME}_test")
+ end
+
+ desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
+ task :migrate do
+ ActiveRecord::Migrator.migrations_paths << File.dirname(__FILE__) + 'db/migrate'
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
+ ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
+ ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
+ end
+ end
+
+ desc "rollback your migration--use STEP=number to step back multiple times"
+ task :rollback do
+ step = (ENV['STEP'] || 1).to_i
+ ActiveRecord::Migrator.rollback('db/migrate', step)
+ Rake::Task['db:version'].invoke if Rake::Task['db:version']
+ end
+
+ desc "Populate the database with dummy data by running db/seeds.rb"
+ task :seed do
+ require APP_ROOT.join('db', 'seeds.rb')
+ end
+
+ desc "Returns the current schema version number"
+ task :version do
+ puts "Current version: #{ActiveRecord::Migrator.current_version}"
+ end
+
+ namespace :test do
+ desc "Migrate test database"
+ task :prepare do
+ system "rake db:migrate RACK_ENV=test"
+ end
+ end
+end
+
+desc 'Start IRB with application environment loaded'
+task "console" do
+ exec "irb -r./config/environment"
+end
+
+task :default => :spec
diff --git a/app/controllers/.gitkeep b/app/controllers/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/controllers/index.rb b/app/controllers/index.rb
new file mode 100644
index 0000000..46dfda7
--- /dev/null
+++ b/app/controllers/index.rb
@@ -0,0 +1,164 @@
+#TODO: -stretch goal- redirect back to previous page if you go to login or register.
+
+#User.cars or User.prices gets cars or prices for that instance of user.
+
+
+get '/' do
+ redirect '/cars'
+end
+
+get '/login' do
+ redirect '/cars' if logged_in?
+
+ erb :login
+end
+
+#authenticates login
+post '/login' do
+ @email = params[:email]
+ @password = params[:password]
+ @user = user_at_email(params[:email])
+
+ if fields_not_blank?( @email, @password )
+ if user_is_authenticated?( @user, @password )
+ session_set_current_user(@user)
+ redirect '/cars'
+ else
+ @login_error = "The email address or password you’ve entered is not valid."
+ erb :login
+ end
+ else
+ @login_error = "Please enter all required fields"
+ erb :login
+ end
+end
+
+# display register page
+get '/register' do
+ @user = nil
+ redirect '/cars' if logged_in?
+ erb :register
+end
+
+# goes to homepage or back to register page
+post '/register' do
+ @name = params[:name]
+ @email = params[:email]
+ @password = params[:password]
+ if any_blank_fields?( @email, @password, @name)
+ @errors = "Please enter all required fields"
+ erb :register
+ else
+ @user = User.create(name: @name, email: @email, password: @password)
+ if @user.errors[:email].any?
+ @error_email = @user.errors[:email][0]
+ erb :register
+ else
+ redirect '/login'
+ end
+ end
+end
+
+#logout
+get '/logout' do
+ session_logout
+ redirect '/'
+end
+
+get '/cars' do
+ erb :car
+end
+
+get '/cars/:id/prices' do |id|
+#shows page of prices for a specific car
+@car = Car.find(id)
+@id = id
+erb :prices
+end
+
+get '/cars/:car_id/prices/new' do |car_id|
+ # erb :new_price if logged_in?
+ # redirect '/login'
+ if logged_in?
+ @car = Car.find(car_id)
+ @id = car_id
+ erb :new_price
+ else
+ redirect '/login'
+ end
+end
+
+#creates a new price for that car.
+post '/cars/:car_id/prices/new' do |car_id|
+ redirect '/login' unless logged_in?
+ @price = Price.create({cost: params[:cost], user_id: session_current_user_id, car_id: car_id })
+ if @price.errors[:cost].any?
+ @errors = @price.errors[:cost][0]
+ @car = Car.find(car_id)
+ @id = car_id
+ erb :new_price
+ else
+ redirect "/cars/#{car_id}/prices"
+ end
+
+end
+
+#show a specific price and who submitted it.
+get '/cars/:car_id/prices/:price_id' do |car_id, price_id|
+ @car = Car.find(car_id)
+ @id = car_id
+ @price_id = price_id
+ @price = Price.find(price_id)
+ @user = @price.user
+ erb :price_id
+end
+
+
+
+#display edit page specific price for car
+get '/cars/:car_id/prices/:price_id/edit' do |car_id, price_id|
+ redirect '/login' unless logged_in?
+ @car = Car.find(car_id)
+ @id = car_id
+ @price_id = price_id
+ @price = Price.find(price_id)
+ @user = @price.user
+
+ if @user != session[:current_user]
+ @access = false
+ @errors = "You're can only edit your submissions"
+ end
+ erb :edit
+end
+
+put '/cars/:car_id/prices/:price_id' do |car_id, price_id|
+ @price = Price.find(price_id)
+ @price.cost = params[:cost]
+ @price.save
+ @user = @price.user
+
+ if @price.valid?
+ redirect "/cars/#{car_id}/prices/#{price_id}"
+ else
+ @error_cost = @price.errors[:cost][0]
+ redirect "/cars/#{car_id}/prices/#{price_id}/edit"
+ end
+end
+
+get '/cars/:car_id/prices/:price_id/delete' do |car_id, price_id|
+ @price = Price.find(price_id)
+ @car_id = car_id
+ erb :delete
+end
+
+
+#deletes a price you've created in the past
+delete '/cars/:car_id/prices/:price_id' do |car_id, price_id|
+ @car_id = car_id
+ @price = Price.find(price_id)
+ @price.destroy
+ redirect "/cars/#{car_id}/prices"
+end
+
+
+
diff --git a/app/helpers/.gitkeep b/app/helpers/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/helpers/README.md b/app/helpers/README.md
new file mode 100644
index 0000000..f3ef772
--- /dev/null
+++ b/app/helpers/README.md
@@ -0,0 +1,32 @@
+# HELPERS
+
+## Basics
+
+Helpers are methods that are defined in a central place but which can be used
+inside of your view templates. An example of a helper is shown in
+`app/views/index.erb` inside where we use the `em` helper.
+
+## Adding helpers
+
+Add helpers here inside of *.rb files inside this directory e.g.:
+`app/helpers/formatting.rb`.
+
+Inside this file define your helpers like:
+
+```
+helpers do
+ def em(text)
+ "#{text} "
+ end
+end
+```
+
+## Reloading
+
+After you create new files containing helpers, you must restart the web server
+so that your changes are reloaded into the running web server process. This is
+because helper files are read *only once* at web-server *startup* time. Also,
+if you add a new helper or alter its implementation, you *also* must restart it
+so that "sourced" (i.e. read in) anew. Other web frameworks do not require
+this restart e.g. Rails but in this starter kit you're best not "bubbling out"
+helpers until your implementation has "gelled."
diff --git a/app/helpers/session_helper.rb b/app/helpers/session_helper.rb
new file mode 100644
index 0000000..8218fde
--- /dev/null
+++ b/app/helpers/session_helper.rb
@@ -0,0 +1,40 @@
+def user_at_email(email)
+ User.find_by_email(email)
+end
+
+def user_is_authenticated?(user, password)
+ return false if user.blank?
+ user.authenticate(password) ? true : false
+end
+
+def logged_in?
+ !!session[:current_user]
+end
+
+def session_set_current_user(user)
+ session[:current_user] = user
+end
+
+def session_current_user_id
+ session[:current_user].id
+end
+
+def session_user_prices
+ session[:current_user].prices
+end
+
+def session_logout
+ session.delete :current_user
+end
+
+def fields_not_blank?(email,password,*name)
+ if !!name[0]
+ !email.blank? && !password.blank? && !name[0].blank?
+ else
+ !email.blank? && !password.blank?
+ end
+end
+
+def any_blank_fields?(email, password, name)
+ email.blank? || password.blank? || name.blank?
+end
\ No newline at end of file
diff --git a/app/models/.gitkeep b/app/models/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/models/README.md b/app/models/README.md
new file mode 100644
index 0000000..12849f7
--- /dev/null
+++ b/app/models/README.md
@@ -0,0 +1,5 @@
+Add your ActiveRecord models here.
+
+You can create them by being in the application root directory and running:
+
+`rake generate:model NAME=User`
diff --git a/app/models/car.rb b/app/models/car.rb
new file mode 100644
index 0000000..9cf20a7
--- /dev/null
+++ b/app/models/car.rb
@@ -0,0 +1,8 @@
+class Car < ActiveRecord::Base
+ has_many :prices
+ has_many :users, through: :prices
+
+ validates :make, presence: true
+ validates :model, presence: true
+ validates :year, presence: true
+end
diff --git a/app/models/price.rb b/app/models/price.rb
new file mode 100644
index 0000000..4c9bcba
--- /dev/null
+++ b/app/models/price.rb
@@ -0,0 +1,7 @@
+class Price < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :car
+validates :cost, presence: {message: "cost can't be blank"}
+validates :cost, format: { with: /\A[0-9]{2,}\z/, message: "Only numbers allowed and no commas" }
+end
+
diff --git a/app/models/user.rb b/app/models/user.rb
new file mode 100644
index 0000000..4c64c5f
--- /dev/null
+++ b/app/models/user.rb
@@ -0,0 +1,27 @@
+class User < ActiveRecord::Base
+ has_many :prices
+ has_many :cars, through: :prices
+
+ validates :email, presence: true
+ validates :email, uniqueness: { message: "email has already been taken" }
+ validates :email, format: { with: /\A[\w]{1,}\.?[\w]{1,}@[a-zA-Z0-9]{2,}\.[a-zA-Z0-9]{2,}\z/, message: "Not a valid email" }
+ validates :name, presence: {message: "Must have a name"}
+ validates :password_hash, presence: true
+
+include BCrypt
+
+ def password
+ @password ||= Password.new(password_hash)
+ end
+
+ def password=(new_password)
+ @password = Password.create(new_password)
+ self.password_hash = @password
+ end
+
+ def authenticate(password)
+ self.password == password
+ end
+
+
+end
diff --git a/app/views/.gitkeep b/app/views/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/views/car.erb b/app/views/car.erb
new file mode 100644
index 0000000..178dbd4
--- /dev/null
+++ b/app/views/car.erb
@@ -0,0 +1,12 @@
+
+
Cars Makes
+
<% Car.all.group_by(&:make).map do |make, value| %>
+ <%= make %>
+
+ <% end %>
+
+
diff --git a/app/views/delete.erb b/app/views/delete.erb
new file mode 100644
index 0000000..5d12360
--- /dev/null
+++ b/app/views/delete.erb
@@ -0,0 +1,10 @@
+<% if !!@price && @price.user == session[:current_user] %>
+Are you sure you want to delete the following price submission: "$<%= @price.cost %>" ?
+
+<% else %>
+Price not found / you're not authorized to delete this.
+<% end %>
\ No newline at end of file
diff --git a/app/views/edit.erb b/app/views/edit.erb
new file mode 100644
index 0000000..a91a599
--- /dev/null
+++ b/app/views/edit.erb
@@ -0,0 +1,25 @@
+
+<% if @user != session[:current_user] %>
+
+<% else %>
+
+
+ <% end %>
\ No newline at end of file
diff --git a/app/views/index.erb b/app/views/index.erb
new file mode 100644
index 0000000..322d703
--- /dev/null
+++ b/app/views/index.erb
@@ -0,0 +1,9 @@
+
\ No newline at end of file
diff --git a/app/views/layout.erb b/app/views/layout.erb
new file mode 100644
index 0000000..9a3c9a0
--- /dev/null
+++ b/app/views/layout.erb
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
find how much people paid...
+
+
+
+
+
+
+
+
+ <%= yield %>
+
+
diff --git a/app/views/login.erb b/app/views/login.erb
new file mode 100644
index 0000000..5b3c582
--- /dev/null
+++ b/app/views/login.erb
@@ -0,0 +1,14 @@
+
+
diff --git a/app/views/new_price.erb b/app/views/new_price.erb
new file mode 100644
index 0000000..a99f039
--- /dev/null
+++ b/app/views/new_price.erb
@@ -0,0 +1,16 @@
+
+
diff --git a/app/views/price_id.erb b/app/views/price_id.erb
new file mode 100644
index 0000000..044eace
--- /dev/null
+++ b/app/views/price_id.erb
@@ -0,0 +1,13 @@
+
<%= @car.year %> <%= @car.make %>
+ <%= @car.model %>
+
+
+
+
$<%= @price.cost %>
+
+
+ edit
+
+
+
Submitted by <%= @user.name %>
+
diff --git a/app/views/prices.erb b/app/views/prices.erb
new file mode 100644
index 0000000..0ce652c
--- /dev/null
+++ b/app/views/prices.erb
@@ -0,0 +1,18 @@
+
+
+
+ <% @car.prices.each do |price| %>
+
+ $<%= price.cost %>
+ <% if price.user == session[:current_user] %>
+ *** submitted ***
+
+ <% end %>
+
+
+
+ <% end %>
+
diff --git a/app/views/register.erb b/app/views/register.erb
new file mode 100644
index 0000000..76af3b1
--- /dev/null
+++ b/app/views/register.erb
@@ -0,0 +1,32 @@
+
+
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000..6036b25
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,6 @@
+# Require config/environment.rb
+require ::File.expand_path('../config/environment', __FILE__)
+
+set :app_file, __FILE__
+
+run Sinatra::Application
diff --git a/config/database.rb b/config/database.rb
new file mode 100644
index 0000000..08c74b7
--- /dev/null
+++ b/config/database.rb
@@ -0,0 +1,42 @@
+# Log queries to STDOUT in development
+if Sinatra::Application.development?
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
+end
+
+# Automatically load every file in APP_ROOT/app/models/*.rb, e.g.,
+# autoload "Person", 'app/models/person.rb'
+#
+# We have to do this in case we have models that inherit from each other.
+# If model Student inherits from model Person and app/models/student.rb is
+# required first, it will throw an error saying "Person" is undefined.
+#
+# With this lazy-loading technique, Ruby will try to load app/models/person.rb
+# the first time it sees "Person" and will only throw an exception if
+# that file doesn't define the Person class.
+#
+# See http://www.rubyinside.com/ruby-techniques-revealed-autoload-1652.html
+Dir[APP_ROOT.join('app', 'models', '*.rb')].each do |model_file|
+ filename = File.basename(model_file).gsub('.rb', '')
+ autoload ActiveSupport::Inflector.camelize(filename), model_file
+end
+
+# Heroku controls what database we connect to by setting the DATABASE_URL environment variable
+# We need to respect that if we want our Sinatra apps to run on Heroku without modification
+db = URI.parse(ENV['DATABASE_URL'] || "postgres://localhost/#{APP_NAME}_#{Sinatra::Application.environment}")
+
+DB_NAME = db.path[1..-1]
+
+# Note:
+# Sinatra::Application.environment is set to the value of ENV['RACK_ENV']
+# if ENV['RACK_ENV'] is set. If ENV['RACK_ENV'] is not set, it defaults
+# to :development
+
+ActiveRecord::Base.establish_connection(
+ :adapter => db.scheme == 'postgres' ? 'postgresql' : db.scheme,
+ :host => db.host,
+ :port => db.port,
+ :username => db.user,
+ :password => db.password,
+ :database => DB_NAME,
+ :encoding => 'utf8'
+)
diff --git a/config/environment.rb b/config/environment.rb
new file mode 100644
index 0000000..2e04cae
--- /dev/null
+++ b/config/environment.rb
@@ -0,0 +1,47 @@
+# Set up gems listed in the Gemfile.
+# See: http://gembundler.com/bundler_setup.html
+# http://stackoverflow.com/questions/7243486/why-do-you-need-require-bundler-setup
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+
+require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
+
+# Require gems we care about
+require 'rubygems'
+
+require 'uri'
+require 'pathname'
+
+require 'pg'
+require 'active_record'
+require 'logger'
+
+require 'sinatra'
+require "sinatra/reloader" if development?
+
+require 'erb'
+require 'faker'
+require 'bcrypt'
+
+# Some helper constants for path-centric logic
+APP_ROOT = Pathname.new(File.expand_path('../../', __FILE__))
+
+APP_NAME = APP_ROOT.basename.to_s
+
+configure do
+ # By default, Sinatra assumes that the root is the file that calls the configure block.
+ # Since this is not the case for us, we set it manually.
+ set :root, APP_ROOT.to_path
+ # See: http://www.sinatrarb.com/faq.html#sessions
+ enable :sessions
+ set :session_secret, ENV['SESSION_SECRET'] || 'this is a secret shhhhh'
+
+ # Set the views to
+ set :views, File.join(Sinatra::Application.root, "app", "views")
+end
+
+# Set up the controllers and helpers
+Dir[APP_ROOT.join('app', 'controllers', '*.rb')].each { |file| require file }
+Dir[APP_ROOT.join('app', 'helpers', '*.rb')].each { |file| require file }
+
+# Set up the database and models
+require APP_ROOT.join('config', 'database')
diff --git a/db/migrate/.gitkeep b/db/migrate/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/db/migrate/20150206080134_create_users.rb b/db/migrate/20150206080134_create_users.rb
new file mode 100644
index 0000000..7e58201
--- /dev/null
+++ b/db/migrate/20150206080134_create_users.rb
@@ -0,0 +1,12 @@
+class CreateUsers < ActiveRecord::Migration
+ def change
+ create_table :users do |t|
+
+ t.string :name
+ t.string :email
+ t.string :password_hash
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20150206080139_create_cars.rb b/db/migrate/20150206080139_create_cars.rb
new file mode 100644
index 0000000..8f5ae64
--- /dev/null
+++ b/db/migrate/20150206080139_create_cars.rb
@@ -0,0 +1,11 @@
+class CreateCars < ActiveRecord::Migration
+ def change
+ create_table :cars do |t|
+ t.string :make
+ t.string :model
+ t.string :year
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20150206080223_create_prices.rb b/db/migrate/20150206080223_create_prices.rb
new file mode 100644
index 0000000..dbe16f5
--- /dev/null
+++ b/db/migrate/20150206080223_create_prices.rb
@@ -0,0 +1,12 @@
+class CreatePrices < ActiveRecord::Migration
+ def change
+ create_table :prices do |t|
+ t.string :cost
+
+ t.integer :car_id
+ t.integer :user_id
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/seeds.rb b/db/seeds.rb
new file mode 100644
index 0000000..1e8cdce
--- /dev/null
+++ b/db/seeds.rb
@@ -0,0 +1,47 @@
+cars = {
+ "Aston Martin" => ["DB9"],
+ "BMW" => ["328i", "M3", "M6", "i8", "i3"],
+ "Chevrolet" => ["Corvette Z06"],
+ "Dodge" => ["Challenger"],
+ "Ford" => ["Focus", "Flex", "Escape", "Fusion"],
+ "Ferrari" => ["California", "458Italia"],
+ "Honda" => ["Fit EX", "Accord EX"],
+ "Jaguar" => ["F-Type R"],
+ "Mercedes" => ["SLS-Class SLS AMG GT Final Edition"],
+ "Nissan" => ["370Z", "Altima"],
+ "Subaru" => ["BRZ", "WRX"],
+ "Tesla" => ["Model S"],
+ "Toyota" => ["FRS"],
+ "Volkwagen" => ["GTI"]
+}
+
+years = (2008..2015).to_a
+
+cars.each do |key, models|
+ models.each do |model|
+ Car.create({ make: key, model: model, year: years.sample })
+ end
+end
+
+user = (1..21).to_a
+car = (1..25).to_a
+
+User.create({name: "Andrew Yan", email: "yandrew@gmail.com", password: "1"})
+Price.create({ cost: 200000,user_id: 1, car_id: 1})
+
+20.times do
+ User.create({name: Faker::Name.name, email: Faker::Internet.email, password:1 })
+end
+
+def fake_cost
+ (10000 + rand(50000)).to_s
+end
+
+60.times do
+ Price.create({cost: fake_cost, user_id: user.sample, car_id: car.sample})
+end
+
+
+
+
+
diff --git a/public/css/application.css b/public/css/application.css
new file mode 100644
index 0000000..f0e0ce8
--- /dev/null
+++ b/public/css/application.css
@@ -0,0 +1,235 @@
+body {
+ color: rgb(75, 147, 130);
+ background-color: #5B6F72;
+}
+
+
+.logins {
+
+ position: absolute;
+ right: 20px;
+ bottom: 5px;
+}
+
+
+
+a {
+ color: rgb(242, 240, 236);
+}
+
+a:hover {
+ color: rgb(160, 33, 95);
+}
+
+
+div {
+
+}
+
+ul {
+
+}
+
+li {
+
+}
+
+a {
+ text-decoration: none;
+ color: rgb(242, 240, 236);
+}
+
+a :visited {
+ text-decoration: none;
+}
+
+a :hover {
+ text-decoration: none;
+}
+
+span {
+
+}
+
+input {
+ line-height: 2em;
+ margin: 8px 5px;
+ border-radius: 5px;
+ background-color: azure;
+}
+
+input[type="submit"] {
+ width: 130px;
+ border-radius: 5px;
+ background-color: azure;
+}
+
+input:hover {
+ border-style:2px solid rgb(57, 84, 168);
+}
+
+div.center-frame h4{
+ color: rgb(228, 179, 104);
+ font-size: 1.2em;
+}
+
+div.error{
+ color: red;
+ font-size: 1em;
+}
+
+div.form-price-add h5 {
+ color: rgb(232, 145, 73);
+ font-size: 1.3em;
+ text-align: center;
+}
+
+div.home_title {
+ height: 500px;
+
+ position: inherit;
+ text-align: center;
+}
+
+div.form-price-add {
+ text-align: center;
+}
+
+div.price-title a{
+ font-size: 1em;
+}
+div.title {
+ position: relative;
+ display: initial;
+ text-align: center;
+}
+
+div.home_title h1 a {
+ text-align: center;
+ color: #6D91CF;
+}
+
+div.home_title h4 {
+ color: #5291A6;
+}
+
+span.signin {
+ color: rgb(216, 134, 54);
+ font-size: 1.5em;
+}
+
+span.error-message {
+ color: rgb(218, 36, 36);
+ font-size: 1em;
+}
+
+ul.header-list {
+ position: relative;
+}
+
+ul.header-list li {
+ list-style: none;
+ display: table-cell;
+ padding: 5px 15px;
+}
+
+
+
+.top_container {
+ position: relative;
+ top: 0px;
+ height: 150px;
+ width: 100%;
+ margin: 0 auto;
+ background-color: #AAA9B3;
+ display: inline-block;
+}
+
+.center-frame{
+ left: 20%;
+ position: absolute;
+}
+.car-price {
+ list-style: none;
+ position: absolute;
+ bottom: 25px;
+ left: 30px;
+}
+
+.error-message {
+ color: red;
+}
+ul.make li.make-li {
+ color: rgb(136, 7, 7);
+ list-style: none;
+ margin: 5px auto;
+ fort-size: 1.2em;
+}
+
+div.price-title a {
+ font-size: 1em;
+}
+
+.price-list {
+ text-align: left;
+ width: 40%;
+ margin: 10px auto;
+}
+
+.price-title h4 {
+ color: rgb(136, 7, 7);
+ font-size: 2em;
+ text-align: center;
+}
+
+.price-title {
+ text-align: center;
+}
+
+.registration-form {
+ border: 2px solid white;
+ text-align: center;
+ margin: 60px auto;
+ padding: 23px;
+ width: 50%;
+ border-radius: 24px;
+ background-color: rgb(77, 120, 121);
+ position: relative;
+}
+
+span.star-marker {
+ color: red;
+}
+
+.subtitle {
+ font-size: medium
+ color: rgb(34, 123, 178)
+}
+
+.sign-in-form {
+ border: 2px solid white;
+ text-align: center;
+ margin: 50px auto;
+ padding: 23px;
+ width: 66%;
+ border-radius: 24px;
+ background-color: rgb(77, 120, 121);
+}
+
+.form-price-add {
+ border: 2px solid white;
+ text-align: center;
+ margin: 50px auto;
+ padding: 23px;
+ width: 45%;
+ border-radius: 24px;
+ background-color: rgb(77, 120, 121);
+}
+
+
+
+
+
+
+
+
diff --git a/public/css/normalize.css b/public/css/normalize.css
new file mode 100644
index 0000000..196d223
--- /dev/null
+++ b/public/css/normalize.css
@@ -0,0 +1,423 @@
+/*! normalize.css v3.0.0 | MIT License | git.io/normalize */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
+ * user zoom.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+ -ms-text-size-adjust: 100%; /* 2 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined in IE 8/9.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 8/9.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+
+audio,
+canvas,
+progress,
+video {
+ display: inline-block; /* 1 */
+ vertical-align: baseline; /* 2 */
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9.
+ * Hide the `template` element in IE, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+ display: none;
+}
+
+/* Links
+ ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+ background: transparent;
+}
+
+/**
+ * Improve readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Address styling not present in IE 8/9, Safari 5, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari 5 and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari 5, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9.
+ */
+
+img {
+ border: 0;
+}
+
+/**
+ * Correct overflow displayed oddly in IE 9.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari 5.
+ */
+
+figure {
+ margin: 1em 40px;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+
+pre {
+ overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+
+/**
+ * 1. Correct color not being inherited.
+ * Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ color: inherit; /* 1 */
+ font: inherit; /* 2 */
+ margin: 0; /* 3 */
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10.
+ */
+
+button {
+ overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8+, and Opera
+ * Correct `select` style inheritance in Firefox.
+ */
+
+button,
+select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+input {
+ line-height: normal;
+}
+
+/**
+ * It's recommended that you don't attempt to style these elements.
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
+ *
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
+ * `font-size` values of the `input`, it causes the cursor style of the
+ * decrement button to change from `default` to `text`.
+ */
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
+ * (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; /* 2 */
+ box-sizing: content-box;
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
+ * Safari (but not Chrome) clips the cancel button when the search input has
+ * padding (and `textfield` appearance).
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+
+optgroup {
+ font-weight: bold;
+}
+
+/* Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+td,
+th {
+ padding: 0;
+}
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..fab98c7
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/js/.gitkeep b/public/js/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/public/js/application.js b/public/js/application.js
new file mode 100644
index 0000000..52e01e6
--- /dev/null
+++ b/public/js/application.js
@@ -0,0 +1,7 @@
+$(document).ready(function() {
+ // This is called after the document has loaded in its entirety
+ // This guarantees that any elements we bind to will exist on the page
+ // when we try to bind to them
+
+ // See: http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
+});
diff --git a/spec/controller_index_spec.rb b/spec/controller_index_spec.rb
new file mode 100644
index 0000000..170c13e
--- /dev/null
+++ b/spec/controller_index_spec.rb
@@ -0,0 +1,12 @@
+require_relative 'spec_helper'
+
+
+describe "Relationships" do
+ it "tests for users prices" do
+ # get '/'
+ test_user = User.find(1)
+ test_user.prices[0].cost.to eq(200000)
+
+ end
+end
+
diff --git a/spec/features/.gitkeep b/spec/features/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..eb9c7d7
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,22 @@
+require 'rubygems'
+
+# All our specs should require 'spec_helper' (this file)
+
+# If RACK_ENV isn't set, set it to 'test'. Sinatra defaults to development,
+# so we have to override that unless we want to set RACK_ENV=test from the
+# command line when we run rake spec. That's tedious, so do it here.
+ENV['RACK_ENV'] ||= 'test'
+
+require File.expand_path("../../config/environment", __FILE__)
+require 'shoulda-matchers'
+require 'rack/test'
+require 'capybara'
+require 'capybara/rspec'
+
+RSpec.configure do |config|
+ config.include Rack::Test::Methods
+end
+
+def app
+ Sinatra::Application
+end