diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..b9e6d5c
Binary files /dev/null and b/.DS_Store differ
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..2eb5c09
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,35 @@
+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 'thin'
+
+gem 'bcrypt'
+
+gem 'gravatarify', '~> 3.0.0'
+
+group :test do
+ gem 'shoulda-matchers'
+ gem 'rack-test'
+ gem 'rspec'
+ gem 'capybara'
+ gem 'faker'
+end
+
+group :test, :development do
+ gem 'rerun'
+ gem 'shotgun'
+ gem 'factory_girl'
+ gem 'sinatra-partial'
+end
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..18cc390
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,127 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activemodel (4.2.0)
+ activesupport (= 4.2.0)
+ builder (~> 3.1)
+ activerecord (4.2.0)
+ activemodel (= 4.2.0)
+ activesupport (= 4.2.0)
+ arel (~> 6.0)
+ activesupport (4.2.0)
+ i18n (~> 0.7)
+ json (~> 1.7, >= 1.7.7)
+ minitest (~> 5.1)
+ thread_safe (~> 0.3, >= 0.3.4)
+ tzinfo (~> 1.1)
+ arel (6.0.0)
+ backports (3.6.4)
+ bcrypt (3.1.10)
+ builder (3.2.2)
+ capybara (2.4.4)
+ mime-types (>= 1.16)
+ nokogiri (>= 1.3.3)
+ rack (>= 1.0.0)
+ rack-test (>= 0.5.4)
+ xpath (~> 2.0)
+ celluloid (0.16.0)
+ timers (~> 4.0.0)
+ daemons (1.1.9)
+ diff-lcs (1.2.5)
+ eventmachine (1.0.6)
+ factory_girl (4.5.0)
+ activesupport (>= 3.0.0)
+ faker (1.4.3)
+ i18n (~> 0.5)
+ ffi (1.9.6)
+ gravatarify (3.0.0)
+ hitimes (1.2.2)
+ i18n (0.7.0)
+ json (1.8.2)
+ listen (2.8.5)
+ celluloid (>= 0.15.2)
+ rb-fsevent (>= 0.9.3)
+ rb-inotify (>= 0.9)
+ mime-types (2.4.3)
+ mini_portile (0.6.2)
+ minitest (5.5.1)
+ multi_json (1.10.1)
+ nokogiri (1.6.6.2)
+ mini_portile (~> 0.6.0)
+ pg (0.18.1)
+ rack (1.6.0)
+ rack-protection (1.5.3)
+ rack
+ rack-test (0.6.3)
+ rack (>= 1.0)
+ rake (10.4.2)
+ rb-fsevent (0.9.4)
+ rb-inotify (0.9.5)
+ ffi (>= 0.5.0)
+ rerun (0.10.0)
+ listen (~> 2.7, >= 2.7.3)
+ rspec (3.2.0)
+ rspec-core (~> 3.2.0)
+ rspec-expectations (~> 3.2.0)
+ rspec-mocks (~> 3.2.0)
+ rspec-core (3.2.0)
+ rspec-support (~> 3.2.0)
+ rspec-expectations (3.2.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.2.0)
+ rspec-mocks (3.2.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.2.0)
+ rspec-support (3.2.1)
+ shotgun (0.9)
+ rack (>= 1.0)
+ shoulda-matchers (2.8.0)
+ 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)
+ sinatra-partial (0.4.0)
+ sinatra
+ thin (1.6.3)
+ daemons (~> 1.0, >= 1.0.9)
+ eventmachine (~> 1.0)
+ rack (~> 1.0)
+ thread_safe (0.3.4)
+ tilt (1.4.1)
+ timers (4.0.1)
+ hitimes
+ tzinfo (1.2.2)
+ 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
+ gravatarify (~> 3.0.0)
+ pg
+ rack-test
+ rake
+ rerun
+ rspec
+ shotgun
+ shoulda-matchers
+ sinatra
+ sinatra-contrib
+ sinatra-partial
+ thin
diff --git a/Planning - Schema, Models, and Features.md b/Planning - Schema, Models, and Features.md
new file mode 100644
index 0000000..74a13de
--- /dev/null
+++ b/Planning - Schema, Models, and Features.md
@@ -0,0 +1,118 @@
+# Schema
+
+#### Shoes
+* brand
+* model
+* price
+* size
+
+#### review
+* author_id (user_id)
+* votes_up
+* comment_body
+* authors_fit_opinion (it fits their foot well or not)
+
+#### Users
+* foot_profile
+* (optional)foot_mature?
+
+#### Foot_profiles
+* size
+
+#### Votes
+* vote_count
+
+# Models
+#### Votes
+* uniqueness scope (AR), combination of voter_id & comment_id must be unique
+
+
+#### User
+* has_many :review
+* belongs_to :foot_profile
+* Method to: View all review made by user, linked by shoe image (active record scopes)
+* Method to: View total votes up/down
+
+#### Foot_profile
+* has_many :users
+
+####Shoe
+* has many :review
+* composite attribute for shoe image based on brand and model naming convention
+
+#### review
+* shoe_id
+* author_id
+* message
+
+
+
+
+#Features
+* Can view all review for all sizes pertaining to a specifc shoe in character-limited divs.
+* Can expand all review on a page with one button.
+* Can view all review made by a user
+
+
+
+
+#Milestones
+####Requirements
+* Portfolio 1: Sinatra RESTful CRUD
+* Portfolio 2: Active Record
+* Portfolio 3: Authentication And Authorization
+* Portfolio 4: HTML and CSS
+* Portfolio 5: Validations and Errors
+
+####User Stories
+* A rock climber can view the site without registering or logging in.
+* A rock climber can register for an account and login to leave reviews and vote(?).
+* A rock climber can search for shoes.
+* A rock climber can read other rock climbers' opinions or reviews of a specific size of a specific model of a shoe.
+* A rock climber can leave a review.
+* A rock climber must say whether a shoe fits the shape of their particular foot as part of their review.
+* A rock climber can add a picture to their review.
+* A rock climber can vote on whether another climber's review is helpful. (?)
+* A rock climber can see a list of the reviews authored by another rock climber.
+* A rock climber can define the profile of their foot, either empirically or with measurements.
+* A rock climber can get the profile of their foot by taking specific measurements.
+* A rock climber can verify the validity of their measurements by taking a picture of their foot from a specific angle with some reference.
+* A rock climber can sort shoes based on the reviews left by rock climbers with similarly shaped feet.
+* A rock climber can see a list of prices from different retailers for each shoe.
+
+
+####Deliverables
+* Readme.md with running instructions
+* **Passion Project A Features & Requirements Chart:**
+
+| Feature | P1 | P2 | P3 | P4 | P5 |
+| ------- | --- | --- | --- | --- | --- |
+| | | | | | |
+
+
+
+
+to-do:
+2.8
+add "review written XXX ago" counter
+add error handling & validations
+add pictures
+
+2.5
+Test connections with fake seeds in db
+Search: ilike(any(array)) (?syntax)
+
+where(product ilike ANY([? ARRAY]))
+
+class Question < Posting
+ has_many :answers
+
+
+ def self.search(string)
+ Question.where("content ILIKE ANY ( array[?] ) OR title ILIKE ANY ( array[?] )", parsed(string), parsed(string))
+ end
+
+ def self.parsed(string)
+ string.tr('^A-Za-z0-9 ', '').split(' ').map {|val| "%#{val}%" }
+ end
+end
diff --git a/README copy.md b/README copy.md
new file mode 100644
index 0000000..3b221fa
--- /dev/null
+++ b/README copy.md
@@ -0,0 +1,305 @@
+# Sinatra Url Shortener
+
+## Learning Competencies
+
+* Test-driven development using rspec and [rack-test][]
+* Map the flow of data through a web application
+* Use redirect
+* Use Active Record callbacks
+* Implement a user authorization scheme to limit unauthorized access to specific pages in a web application
+* Deploy your application to Heroku
+
+## Summary
+
+We're going to build a simple link shortener, a la [bitly][].
+
+You'll have one model named `Url`. The table for this model stores a list of
+URLs that people have entered.
+
+## Releases
+
+### Release 0: Simple Shortener
+
+Start with the empty Sinatra skeleton.
+
+We have one resource: `Urls`. For our controllers, we have a route that lists
+`Url` objects and another route that, when POSTed to, creates a `Url` object.
+
+Let's test-drive these routes!
+
+Create a file in the `spec/` directory that corresponds to your controller.
+Maybe call it something like `index_controller_spec.rb`. Open this file in your
+editor and write a controller spec for `GET /urls` using the syntax provided by
+[rack-test][]. The [Sinatra testing documentation][] also has documentation
+about how to test a controller.
+
+Write a failing test first. After you've made it pass by implementing the route,
+write a failing test for the `POST /urls` route. Keep the
+
+1. Given
+2. When
+3. Then
+
+steps in mind, since they'll help you set up the test for your POST route. Here's
+the general format for an empty controller test:
+
+```ruby
+require 'spec_helper'
+describe "index_controller" do
+ # specs go here!
+end
+```
+
+We'll also need a route that redirects us to the full (unshortened) URL. As
+always, write a test first. If you've never used bitly, use it now to get a
+feel for how it works.
+
+Now that you've written tested controllers, the controller methods should look
+like this:
+
+```ruby
+get '/' do
+ # let user create new short URL, display a list of shortened URLs
+end
+
+post '/urls' do
+ # create a new Url
+end
+
+# e.g., /q6bda
+get '/:short_url' do
+ # redirect to appropriate "long" URL
+end
+```
+
+Use a `before_save` callback in the `Url` model to generate the short URL.
+**Write a test** for the model method you created that generates the short URL,
+but don't worry about testing that the `before_save` callback fires. We'll trust
+that ActiveRecord has been thoroughly tested.
+
+### Release 1: Add a Counter!
+
+Add a `click_count` field to your `urls` table, which keeps track of how many
+times someone has visited the shortened URL. Add code to the appropriate place
+in your controller code so that any time someone hits a short URL the counter
+for the appropriate `Url` is incremented by 1. You can (and should) also write
+a test for this.
+
+### Release 2: User Authentication
+
+Now it's time for things to get complicated. Let's implement a login and logout
+feature for our URL shortener!
+
+The core flow of the app should remain the same, however a person might choose
+to log in or create an account. In the event that they're logged in when they shorten
+a URL, this `Url` should now be associated with their user account. In other words,
+a `Url` belongs to a `User` and a `User` has many `Urls`.
+
+**Note**: Don't worry about implement the above user-centric logic yet. First
+get all the URL shortening and user authentication code working. **Feel free to
+spike on this** and forego TDD while you figure out user authentication, we'll
+come back to repair broken tests in a bit. Make sure people can log in and can
+shorten URLs regardless of whether they're logged in or not.
+
+There's going to be a lot going on in your controller! Try to keep the code as
+readable and organized as possible. A file structure like this might make sense:
+
+1. `app/controllers/urls.rb`, which contains the routes related to listing, creating, and redirecting `Url` objects
+2. `app/controllers/sessions.rb`, which contains the routes related to logging in and logging out
+3. `app/controllers/users.rb`, which contains the routes related to creating, displaying, and editing users
+
+### Release 3: Conditional Logic
+
+Now that you've got basic user authentication and URL shortening working, it's
+time to stitch these features together. Depending on whether a user is signed
+in, your site will change dynamically.
+
+People should be able to create short URLs regardless of whether they're logged
+in or not (that is, the `user_id` field on the `urls` table could possibly be
+`NULL`).
+
+However, if a user *is* logged in, when we create a URL it should set the
+`user_id` to whatever the `user_id` of the currently logged-in user is. This
+information *should not* be a part of the form that a user submits — it
+would be trivial for someone to change the content of the form and submit as
+any user. The information should, instead, be stored in the users' sessions.
+
+Users should now be able to view their URLs on their profile page, which should
+look like this:
+
+```ruby
+get '/users/:id' do
+end
+```
+
+This should display a user's profile, which lists all the links that a
+particular user has created. If I'm viewing my *own* profile page, show the
+number of clicks next to each link so I can see how awesome my link-sharing
+skills are.
+
+Since you'll be checking the session in every route, your routes are probably pretty
+repetetive. But theres a better way! You can create helper methods to DRY up your
+controller and view code. You could use something like this:
+
+```ruby
+helpers do
+ # This will return the current user, if they exist
+ # Replace with code that works with your application
+ def current_user
+ if session[:user_id]
+ @current_user ||= User.find_by_id(session[:user_id])
+ end
+ end
+
+ # Returns true if current_user exists, false otherwise
+ def logged_in?
+ !current_user.nil?
+ end
+end
+```
+
+Your controller can now call `current_user` to get the currently authenticated
+user, if they exist. This means we don't have to rely on user-submitted data
+to determine what user created a short URL.
+
+
+
+### Release 4: Fix Your Broken Tests and Write New Ones!
+All of this dynamic content has probably caused your tests to break. But that's
+ok! They can be fixed! You can fake a user's session using rack-test. The 'GET'
+and 'POST' methods take an optional third argument that corresponds to the
+rack environment hash (where information about sessions is stored). It looks
+something like this:
+
+```ruby
+it "should create a new post" do
+ fake_params = { title: "some title", content: "some content" }
+ fake_session = { 'rack.session' => { user_id: 20 } }
+ expect{
+ post '/some_route', fake_params, fake_session
+ }.to change{ Post.count }.by(1)
+end
+```
+
+You should also write tests to check each branch of your conditionals (if/else)
+that correspond to user authentication.
+
+
+### Release 5: Add Validations (Optional)
+
+Test-drive adding a validation to your `Url` model so that only `Urls` with
+valid URLs are saved to the database. Read up on [ActiveRecord validations][].
+You can use ActiveRecord's `valid?` instance method in your test to check if
+the validations are working.
+
+What constitutes a "valid URL" is up to you. It's a sliding scale, from
+validations that would permit lots of invalid URLs to validations that might
+reject lots of valid URLs. When you get into it you'll see that expressing the
+fact "x is a valid URL" in Ruby Land or SQL Land is never perfect.
+
+For example, the valid URL could range across:
+
+**A valid URL is...**
+
+* Any non-empty string
+* Any non-empty string that starts with "http://" or "https://"
+* Any string that the [Ruby URI module][URI module] says is valid
+* Any URL-looking thing which responds to a HTTP request, i.e., we actually check to see if the URL is accessible via HTTP
+
+Some of these are easily expressible in SQL Land. Some of these are hard to
+express in SQL Land, but ActiveRecord comes with pre-built validation helpers
+that make it easy to express in Ruby Land. Others require [custom
+validations][] that express logic unique to our application domain.
+
+The rule of thumb is that where we can, we want to always express constraints
+in Ruby Land and also express them in SQL Land where feasible.
+
+
+### Release 6: Add Error Handling (Optional)
+
+When you try to save (create or update) an ActiveRecord object that has invalid
+data, ActiveRecord will fail. Some methods like `create!` and `save!` throw an
+exception. Others like `create` (without the `!`, the bang) return the resulting
+object whether the object was saved successfully to the database or not, while
+`save` will return `false` if `perform_validation` is true and any validations
+fail. See [create][] and [save][] for more information.
+
+Remember, you can call [valid? or invalid?][valid invalid] on an ActiveRecord
+object to see whether its data is valid or invalid.
+
+Use `valid?`, `invalid?`, and the [errors][] method to display a helpful error message if a user
+enters an invalid URL. This will give them a change to correct their error.
+
+## Optimize Your Learning
+
+### More on Validations, Constraints, and Database Consistency
+
+We often want to put constraints on what sort of data can go into our database.
+This way we can guarantee that all data in the database conforms to certain
+standards, e.g., there are no users missing an email address. Guarantees of
+this kind — ensuring that the data in our database is never confusing or
+contradictory or partially changed or otherwise invalid — are called
+**consistency**.
+
+If we think of this as a fact from Fact Land, these constraints look like:
+
+* A user must have a first\_name
+* A user must have an email
+* Two user's can't have the same email address, or equivalently, each user's email must be unique
+* A Craigslist post's URL must be a valid URL, for some reasonable definition of valid
+
+These facts can be recorded in both SQL Land and in Ruby Land, like this:
+
+
+
+
Fact Land
+
SQL Land
+
Ruby Land
+
+
+
A user must have an email address
+
NOT NULL constraint on email field
+
validates :email, :presence => true
+
+
+
A user must have a first name
+
NOT NULL constraint on first_name field
+
validates :first_name, :presence => true
+
+
+
A user's email address must be unique
+
UNIQUE INDEX on email field
+
validates :email, :uniqueness => true
+
+
+
+### Release 7: Deployment (Optional)
+
+You're feature complete with 100% test coverage. It's time to push this thing into
+production! Get the app up on Heroku, and call it a night.
+
+## Resources
+
+* [Bit.ly, a url shortening service][bitly]
+* [ActiveRecord validations][]
+* [URI module][]
+* [Active record custom validations][custom validations]
+* [ActiveRecord create][create]
+* [ActiveRecord save][save]
+* [ActiveRecord's valid? & invalid?][valid invalid]
+* [ActiveRecord's errors object][errors]
+* [HTTP status codes][]
+* [HTTP status cats][]
+
+[bitly]: http://bitly.com/
+[ActiveRecord validations]: http://guides.rubyonrails.org/active_record_validations.html
+[URI module]: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/uri/rdoc/URI.html
+[custom validations]: http://guides.rubyonrails.org/active_record_validations.html#performing-custom-validations
+[create]: http://apidock.com/rails/ActiveRecord/Base/create/class
+[Sinatra testing documentation]: http://www.sinatrarb.com/testing.html#rspec
+[save]: http://apidock.com/rails/ActiveRecord/Base/save
+[valid invalid]: http://guides.rubyonrails.org/active_record_validations.html#valid-questionmark-and-invalid-questionmark
+[errors]: http://guides.rubyonrails.org/active_record_validations.html#validations-overview-errors
+[HTTP status codes]: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
+[HTTP status cats]: http://httpcats.herokuapp.com/
+[rack-test]: https://github.com/brynary/rack-test#readme
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..5380f6e
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,181 @@
+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 RESTful routes for NOUN"
+ task :controller do
+ unless ENV.has_key?('NOUN')
+ raise "Must specify controller name, e.g., rake generate:controller NOUN=category"
+ end
+
+ require 'active_support/inflector'
+ noun = ActiveSupport::Inflector.pluralize(ENV['NOUN'])
+
+ file_contents = <<-CONTROLLER
+# get a list of #{noun}
+get '/#{noun}' do
+end
+# get a form to add a new #{noun}
+get '/#{noun}/new' do
+end
+# add a new #{noun}
+post '/#{noun}' do
+end
+# get a specific instance of #{noun}
+get '/#{noun}/:id' do
+end
+# get a form to edit a specific instance of #{noun}
+get '/#{noun}/:id/edit' do
+end
+# edit a specific instance of #{noun}
+put '/#{noun}/:id' do
+end
+# delete a specific instance of #{noun}
+delete '/#{noun}/:id' do
+end
+ CONTROLLER
+ controller_path = APP_ROOT.join('app', 'controllers', "#{ENV['NOUN']}.rb")
+ File.write(controller_path, file_contents)
+ end
+
+ 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')
+ generate_shoes
+ generate_users
+ generate_reviews
+ 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..0dca457
--- /dev/null
+++ b/app/controllers/index.rb
@@ -0,0 +1,63 @@
+get '/session-viewer' do
+ session.inspect
+end
+
+get '/session-reset' do
+ session[:user_password] = nil
+ session[:user_id] = nil
+ session.inspect
+end
+
+get '/' do
+ @shoes = ["La Sportiva Solution", "Mad Rock Shark", "Evolv Shaman", "Tenaya Oasi"]
+ erb :index
+end
+
+
+
+get '/logout' do
+ session.clear
+ redirect '/'
+end
+
+get '/login/?' do
+ erb :login
+end
+
+get '/login/again' do
+ erb :login_again
+end
+
+post '/login' do
+ user = User.find_by(email: params[:email])
+ if user.nil? # If email doesn't exist, try again.
+ redirect '/login/again'
+ else # If email exists, try to authenticate
+ if user.authenticate(params[:password])
+ session[:user_id] = user.id
+ session[:user_password] = user.password
+ redirect "/shoes"
+ else
+ redirect '/login/again'
+ end
+ end
+end
+
+# get '/register' do
+
+# erb :register
+# end
+# ### DEPRECATED, MOVED INTO USER CONTROLLER
+# post '/register' do
+# if User.find_by(username: params[:username]).nil? && User.find_by(email: params[:email]).nil?
+# User.create(username: params[:username], email: params[:email], password_hash: params[:password])
+# user = User.find_by(username: params[:username])
+# session[:user_id] = user.id
+# user.password = params[:password]
+# user.save
+# else
+# redirect '/register' #<< partial (: invalid_user )
+# end
+# end
+
+# register login
diff --git a/app/controllers/reviews.rb b/app/controllers/reviews.rb
new file mode 100644
index 0000000..c5c8d8a
--- /dev/null
+++ b/app/controllers/reviews.rb
@@ -0,0 +1,25 @@
+# get a list of comments
+get '/reviews' do
+end
+# get a form to add a new reviews
+get '/reviews/new' do
+
+ erb :new_review
+end
+# add a new reviews
+post '/reviews' do
+ Review.create(message: params[:message], shoe_id: session[:last_shoe_id], author_id:session[:user_id])
+ redirect "/shoes/#{session[:last_shoe_id]}"
+end
+# get a specific instance of reviews
+get '/reviews/:id' do
+end
+# get a form to edit a specific instance of reviews
+get '/reviews/:id/edit' do
+end
+# edit a specific instance of reviews
+put '/reviews/:id' do
+end
+# delete a specific instance of reviews
+delete '/reviews/:id' do
+end
diff --git a/app/controllers/shoes.rb b/app/controllers/shoes.rb
new file mode 100644
index 0000000..219f09e
--- /dev/null
+++ b/app/controllers/shoes.rb
@@ -0,0 +1,38 @@
+# get a list of shoes
+
+before '/shoes/*' do
+ # redirect "/login" unless authorized? # in helpers/session.rb
+end
+
+get '/shoes/?' do
+ erb :shoes
+end
+
+# get '/shoes/:id' do
+# @shoe = Shoe.find(params[:id])
+# # erb :shoe_instance
+# erb :shoe_instance
+# end
+# # get a form to edit a specific instance of shoes
+get '/shoes/:id/new_review' do
+ session[:last_shoe_id] = params[:id]
+ redirect '/reviews/new'
+end
+
+get '/shoes/:display_name' do
+ keywords = params[:display_name].split(" ").map!{|word| "%"+word+"%"}
+ matches = Shoe.where('display_name ilike any ( array[?] )', keywords)
+ matches.to_json
+end
+
+get '/shoesearch' do
+ keywords = params[:shoeBarInput].split(" ").map!{|word| "%"+word+"%"}
+ @matches = Shoe.where('display_name ilike any ( array[?] )', keywords)
+ erb :shoe_list, layout: false
+end
+# # edit a specific instance of shoes
+# put '/shoes/:id' do
+# end
+# # delete a specific instance of shoes
+# delete '/shoes/:id' do
+# end
diff --git a/app/controllers/users.rb b/app/controllers/users.rb
new file mode 100644
index 0000000..25f8846
--- /dev/null
+++ b/app/controllers/users.rb
@@ -0,0 +1,36 @@
+# get a list of users
+get '/users' do
+end
+# get a form to add a new users
+get '/users/new' do
+
+ erb :new_user
+end
+# add a new users
+post '/users' do
+ session[:errors] = nil
+ user = User.create(username: params[:username], email: params[:email], password: params[:password])
+ if user.errors.any?
+ session[:errors] = user.display_errors
+ redirect '/users/new' #<< partial (: invalid_user )
+ elsif
+ session[:user_id] = user.id
+ session[:user_password] = user.password
+ redirect '/'
+ end
+end
+# get a specific instance of users
+get '/users/:username' do
+ @user = User.find_by(username:params[:username])
+ @shoes_with_reviews = @user.shoes_with_reviews(@user.id)
+ erb :user_profile
+end
+# get a form to edit a specific instance of users
+get '/users/:id/edit' do
+end
+# edit a specific instance of users
+put '/users/:id' do
+end
+# delete a specific instance of users
+delete '/users/:id' do
+end
diff --git a/app/helpers/.gitkeep b/app/helpers/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/helpers/README b/app/helpers/README
new file mode 100644
index 0000000..eb4b902
--- /dev/null
+++ b/app/helpers/README
@@ -0,0 +1,9 @@
+Add helpers here as *.rb files, e.g.,
+
+app/helpers/formatting.rb
+
+helpers do
+ def em(text)
+ "#{text}"
+ end
+end
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/navbar.rb b/app/helpers/navbar.rb
new file mode 100644
index 0000000..508a3a1
--- /dev/null
+++ b/app/helpers/navbar.rb
@@ -0,0 +1,16 @@
+def current_user_exist?
+ !session[:user_id].nil?
+end
+
+def current_user_username
+ User.find(session[:user_id]).username
+end
+
+def responsive_login_form
+ if current_user_exist?
+ return "#{current_user_username}. logout"
+ else
+ return "login"
+ end
+
+end
diff --git a/app/helpers/session.rb b/app/helpers/session.rb
new file mode 100644
index 0000000..faa9d98
--- /dev/null
+++ b/app/helpers/session.rb
@@ -0,0 +1,46 @@
+def authorized?
+ unless User.find_by(id: session[:user_id])
+ p "User not found!"*100
+ return false
+ end
+ correct_password = User.find(session[:user_id]).password_hash
+
+ if correct_password == session[:user_password]
+ puts "="*100+"\n passwords match\n"+"="*100
+ return true
+ elsif correct_password != session[:user_password]
+ puts "="*100
+ puts "Passwords don't match."
+ puts "passwords are:\n correct_password:\n#{correct_password}\n ssesion_password:\n#{session[:user_password]}"
+ puts "="*100
+ return false
+ else
+ puts "="*100+"\n what?? helpers\\session.rb \n"+"="*100
+ end
+end
+ # _____
+ # ,---';;;;;`--.
+ # ,';;;;;; '''''''`-,
+ # ; ;;;;,,;;;;;;;;;;;`;
+ # ` ;;; ; ;;;;;;;;,-'`-;
+ # ` ;;;;' ;;; ;;;; ,-'~
+ # /\ /\ ;' ;;;;;;; ,-'
+ # ,--`/ ^; ;:;;;; ;
+ # .' `. ;;;;; `.
+ # ,' (O) ; ;; ;;;; `.
+ # (v}' ,' ; ;; ;;;; `.
+ # `-.--' _,'`. :;;; ;;; :
+ # _._ ~`---' ,- `.`.;;;;;; ;`.
+ # /___\ ; ,' : . ;; ;; ;;
+ # c|##c==-.__; `-. ; ;;;;; ;
+ # c:##c==,_ ` ,' `-.;;;;;;;;
+ # `----' `------', `.; ;;;;;
+ # : __,----. , `.;;;;;
+ # ,'`. ,' , ' ` ;;;;;
+ # : `.,' ,` , ,';;
+ # `._ : ,` ,_,,'
+ # __,-' `-`_` ____,-'
+ # Ccc_,----'_`--' _)
+ # CCcc_,----'
+
+ #WHATUP TWADDY
diff --git a/app/helpers/url_helper.rb b/app/helpers/url_helper.rb
new file mode 100644
index 0000000..1e5488e
--- /dev/null
+++ b/app/helpers/url_helper.rb
@@ -0,0 +1,7 @@
+
+helpers do
+ def crop_url(url)
+ url.length > 20 ? url[0..30]+".."+url[-5..-1] : url
+ end
+
+end
diff --git a/app/models/.gitkeep b/app/models/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/models/README b/app/models/README
new file mode 100644
index 0000000..8316832
--- /dev/null
+++ b/app/models/README
@@ -0,0 +1,5 @@
+Add your ActiveRecord models here.
+
+You can create them by being in the application root directory and running, e.g.,
+
+rake generate:model NAME=User
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/foot_profile.rb b/app/models/foot_profile.rb
new file mode 100644
index 0000000..074e6d4
--- /dev/null
+++ b/app/models/foot_profile.rb
@@ -0,0 +1,7 @@
+class FootProfile < ActiveRecord::Base
+ has_many :users
+ enum forefoot_width: [ :small, :medium, :large]
+ enum heel_width: [ :small, :medium, :large]
+ enum foot_length: [ :small, :medium, :large]
+ # http://stackoverflow.com/questions/23192516/how-to-use-enumrails-4-1
+end
diff --git a/app/models/review.rb b/app/models/review.rb
new file mode 100644
index 0000000..e222bf3
--- /dev/null
+++ b/app/models/review.rb
@@ -0,0 +1,9 @@
+class Review < ActiveRecord::Base
+ belongs_to :author, class_name: "User", foreign_key: 'author_id'
+ belongs_to :shoe
+ has_many :votes
+
+ # def self.serve(shoe_id)
+ # Shoe.find
+ # end
+end
diff --git a/app/models/shoe.rb b/app/models/shoe.rb
new file mode 100644
index 0000000..71ba668
--- /dev/null
+++ b/app/models/shoe.rb
@@ -0,0 +1,16 @@
+class Shoe < ActiveRecord::Base
+ has_many :reviews
+
+ def generate_display_name
+ self.display_name = self.brand + " " + self.model
+ end
+
+ def image_path
+ path = generate_display_name
+ path.gsub(" ", "-").gsub("\'", "")
+ end
+
+ before_save :generate_display_name
+
+
+end
diff --git a/app/models/user.rb b/app/models/user.rb
new file mode 100644
index 0000000..cbae3da
--- /dev/null
+++ b/app/models/user.rb
@@ -0,0 +1,52 @@
+class User < ActiveRecord::Base
+ has_many :reviews , class_name: "Review", foreign_key: "author_id"
+ belongs_to :foot_profile
+
+ def all_comments
+ # active record scopes
+ end
+
+ def upvote_score
+ # Vote.where()
+ end
+ # users.password_hash in the database is a :string
+
+ def password
+ @password ||= BCrypt::Password.new(password_hash)
+ end
+
+ def password=(new_password)
+ @password = BCrypt::Password.create(new_password)
+ self.password_hash = @password
+ end
+
+ def authenticate(password)
+ self.password == password
+ end
+
+ def shoes_with_reviews(user_id)
+ user = User.find(user_id)
+ shoes = user.reviews.map(&:shoe)
+ reviews = user.reviews
+ Hash[shoes.zip(reviews)]
+ end
+
+# validations
+# validates :username, :email, presence: true, uniqueness: true
+# validate :valid_email #, on: :create
+ def valid_email
+ errors.add :email, "is invalid" unless self.email =~ /\A[\w+]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
+ end
+
+ def display_errors
+ html = []
+ self.errors.messages.each_pair do |attribute, errors|
+ html << "#{attribute}: "
+ errors.each do |error| "error"
+ html << "#{error} "
+ end
+ end
+ return html.join("")
+ end
+
+end
diff --git a/app/models/vote.rb b/app/models/vote.rb
new file mode 100644
index 0000000..7d0f59c
--- /dev/null
+++ b/app/models/vote.rb
@@ -0,0 +1,5 @@
+class Vote < ActiveRecord::Base
+ belongs_to :voter, class_name: "User"
+ belongs_to :review
+
+end
diff --git a/app/views/.gitkeep b/app/views/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/app/views/footer.erb b/app/views/footer.erb
new file mode 100644
index 0000000..e69de29
diff --git a/app/views/header.erb b/app/views/header.erb
new file mode 100644
index 0000000..e69de29
diff --git a/app/views/index.erb b/app/views/index.erb
new file mode 100644
index 0000000..20c86d7
--- /dev/null
+++ b/app/views/index.erb
@@ -0,0 +1,18 @@
+
+