-
-
Save mike-burns/9b4135f4c83c6331d4c0 to your computer and use it in GitHub Desktop.
Diff between suspenders and rails
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/.gitignore b/.gitignore | |
index eb3489a..080a3b3 100644 | |
--- a/.gitignore | |
+++ b/.gitignore | |
@@ -13,3 +13,11 @@ | |
# Ignore all logfiles and tempfiles. | |
/log/*.log | |
/tmp | |
+public/system | |
+*.DS_Store | |
+coverage/* | |
+*.swp | |
+rerun.txt | |
+tags | |
+!.keep | |
+vendor/bundler_gems | |
diff --git a/.rspec b/.rspec | |
new file mode 100644 | |
index 0000000..53607ea | |
--- /dev/null | |
+++ b/.rspec | |
@@ -0,0 +1 @@ | |
+--colour | |
diff --git a/Gemfile b/Gemfile | |
index 5367a9a..6f003dd 100644 | |
--- a/Gemfile | |
+++ b/Gemfile | |
@@ -5,7 +5,7 @@ gem 'rails', '3.2.8' | |
# Bundle edge Rails instead: | |
# gem 'rails', :git => 'git://github.com/rails/rails.git' | |
-gem 'sqlite3' | |
+gem 'pg' | |
# Gems used only for assets and not required | |
@@ -21,6 +21,42 @@ group :assets do | |
end | |
gem 'jquery-rails' | |
+gem 'clearance' | |
+gem 'thin' | |
+gem 'high_voltage' | |
+gem 'paperclip' | |
+gem 'formtastic' | |
+gem 'flutie' | |
+gem 'bourbon' | |
+gem 'airbrake' | |
+gem 'therubyracer' | |
+ | |
+group :development do | |
+ gem 'foreman' | |
+end | |
+ | |
+group :development, :test do | |
+ gem 'guard' | |
+ gem 'guard-spork' | |
+ gem 'rspec-rails', '~> 2.9.0' | |
+ gem 'sham_rack' | |
+end | |
+ | |
+group :test do | |
+ gem 'cucumber-rails', '1.3.0', :require => false | |
+ gem 'capybara-webkit', '~> 0.11.0' | |
+ gem 'factory_girl_rails' | |
+ gem 'bourne' | |
+ gem 'database_cleaner' | |
+ gem 'timecop' | |
+ gem 'shoulda-matchers' | |
+ gem 'launchy' | |
+end | |
+ | |
+group :staging, :production do | |
+ gem 'newrelic_rpm' | |
+end | |
+ | |
# To use ActiveModel has_secure_password | |
# gem 'bcrypt-ruby', '~> 3.0.0' | |
diff --git a/Gemfile.lock b/Gemfile.lock | |
index ef2fa3f..12b5992 100644 | |
--- a/Gemfile.lock | |
+++ b/Gemfile.lock | |
@@ -28,8 +28,32 @@ GEM | |
activesupport (3.2.8) | |
i18n (~> 0.6) | |
multi_json (~> 1.0) | |
+ addressable (2.3.2) | |
+ airbrake (3.1.4) | |
+ builder | |
+ girl_friday | |
arel (3.0.2) | |
+ bourbon (2.1.1) | |
+ sass (>= 3.1) | |
+ bourne (1.1.2) | |
+ mocha (= 0.10.5) | |
builder (3.0.3) | |
+ capybara (1.1.2) | |
+ mime-types (>= 1.16) | |
+ nokogiri (>= 1.3.3) | |
+ rack (>= 1.0.0) | |
+ rack-test (>= 0.5.4) | |
+ selenium-webdriver (~> 2.0) | |
+ xpath (~> 0.1.4) | |
+ capybara-webkit (0.11.0) | |
+ capybara (>= 1.0.0, < 1.2) | |
+ json | |
+ childprocess (0.3.5) | |
+ ffi (~> 1.0, >= 1.0.6) | |
+ clearance (0.16.3) | |
+ diesel (~> 0.1.5) | |
+ rails (>= 3.0) | |
+ cocaine (0.3.1) | |
coffee-rails (3.2.2) | |
coffee-script (>= 2.2.0) | |
railties (~> 3.2.0) | |
@@ -37,9 +61,49 @@ GEM | |
coffee-script-source | |
execjs | |
coffee-script-source (1.3.3) | |
+ connection_pool (0.9.2) | |
+ cucumber (1.2.1) | |
+ builder (>= 2.1.2) | |
+ diff-lcs (>= 1.1.3) | |
+ gherkin (~> 2.11.0) | |
+ json (>= 1.4.6) | |
+ cucumber-rails (1.3.0) | |
+ capybara (>= 1.1.2) | |
+ cucumber (>= 1.1.8) | |
+ nokogiri (>= 1.5.0) | |
+ daemons (1.1.9) | |
+ database_cleaner (0.8.0) | |
+ diesel (0.1.5) | |
+ railties | |
+ diff-lcs (1.1.3) | |
erubis (2.7.0) | |
+ eventmachine (1.0.0) | |
execjs (1.4.0) | |
multi_json (~> 1.0) | |
+ factory_girl (4.1.0) | |
+ activesupport (>= 3.0.0) | |
+ factory_girl_rails (4.1.0) | |
+ factory_girl (~> 4.1.0) | |
+ railties (>= 3.0.0) | |
+ ffi (1.1.5) | |
+ flutie (1.3.3) | |
+ foreman (0.59.0) | |
+ thor (>= 0.13.6) | |
+ formtastic (2.2.1) | |
+ actionpack (>= 3.0) | |
+ gherkin (2.11.2) | |
+ json (>= 1.4.6) | |
+ girl_friday (0.10.0) | |
+ connection_pool (~> 0.9.0) | |
+ guard (1.3.3) | |
+ listen (>= 0.4.2) | |
+ thor (>= 0.14.6) | |
+ guard-spork (1.2.0) | |
+ childprocess | |
+ guard (>= 1.1) | |
+ spork (>= 0.8.4) | |
+ sys-proctable | |
+ high_voltage (1.2.0) | |
hike (1.2.1) | |
i18n (0.6.1) | |
journey (1.0.4) | |
@@ -47,12 +111,30 @@ GEM | |
railties (>= 3.1.0, < 5.0) | |
thor (~> 0.14) | |
json (1.7.5) | |
+ launchy (2.1.2) | |
+ addressable (~> 2.3) | |
+ libv8 (3.3.10.4) | |
+ libwebsocket (0.1.5) | |
+ addressable | |
+ listen (0.5.2) | |
mail (2.4.4) | |
i18n (>= 0.4.0) | |
mime-types (~> 1.16) | |
treetop (~> 1.4.8) | |
+ metaclass (0.0.1) | |
mime-types (1.19) | |
+ mocha (0.10.5) | |
+ metaclass (~> 0.0.1) | |
multi_json (1.3.6) | |
+ newrelic_rpm (3.4.2.1) | |
+ nokogiri (1.5.5) | |
+ paperclip (3.2.0) | |
+ activemodel (>= 3.0.0) | |
+ activerecord (>= 3.0.0) | |
+ activesupport (>= 3.0.0) | |
+ cocaine (>= 0.0.2) | |
+ mime-types | |
+ pg (0.14.1) | |
polyglot (0.3.3) | |
rack (1.4.1) | |
rack-cache (1.2) | |
@@ -79,18 +161,49 @@ GEM | |
rake (0.9.2.2) | |
rdoc (3.12) | |
json (~> 1.4) | |
+ rspec (2.9.0) | |
+ rspec-core (~> 2.9.0) | |
+ rspec-expectations (~> 2.9.0) | |
+ rspec-mocks (~> 2.9.0) | |
+ rspec-core (2.9.0) | |
+ rspec-expectations (2.9.1) | |
+ diff-lcs (~> 1.1.3) | |
+ rspec-mocks (2.9.0) | |
+ rspec-rails (2.9.0) | |
+ actionpack (>= 3.0) | |
+ activesupport (>= 3.0) | |
+ railties (>= 3.0) | |
+ rspec (~> 2.9.0) | |
+ rubyzip (0.9.9) | |
sass (3.2.1) | |
sass-rails (3.2.5) | |
railties (~> 3.2.0) | |
sass (>= 3.1.10) | |
tilt (~> 1.3) | |
+ selenium-webdriver (2.25.0) | |
+ childprocess (>= 0.2.5) | |
+ libwebsocket (~> 0.1.3) | |
+ multi_json (~> 1.0) | |
+ rubyzip | |
+ sham_rack (1.3.4) | |
+ rack | |
+ shoulda-matchers (1.3.0) | |
+ activesupport (>= 3.0.0) | |
+ spork (0.9.2) | |
sprockets (2.1.3) | |
hike (~> 1.2) | |
rack (~> 1.0) | |
tilt (~> 1.1, != 1.3.0) | |
- sqlite3 (1.3.6) | |
+ sys-proctable (0.9.1) | |
+ therubyracer (0.10.2) | |
+ libv8 (~> 3.3.10) | |
+ thin (1.5.0) | |
+ daemons (>= 1.0.9) | |
+ eventmachine (>= 0.12.6) | |
+ rack (>= 1.0.0) | |
thor (0.16.0) | |
tilt (1.3.3) | |
+ timecop (0.5.2) | |
treetop (1.4.10) | |
polyglot | |
polyglot (>= 0.3.1) | |
@@ -98,14 +211,39 @@ GEM | |
uglifier (1.3.0) | |
execjs (>= 0.3.0) | |
multi_json (~> 1.0, >= 1.0.2) | |
+ xpath (0.1.4) | |
+ nokogiri (~> 1.3) | |
PLATFORMS | |
ruby | |
DEPENDENCIES | |
+ airbrake | |
+ bourbon | |
+ bourne | |
+ capybara-webkit (~> 0.11.0) | |
+ clearance | |
coffee-rails (~> 3.2.1) | |
+ cucumber-rails (= 1.3.0) | |
+ database_cleaner | |
+ factory_girl_rails | |
+ flutie | |
+ foreman | |
+ formtastic | |
+ guard | |
+ guard-spork | |
+ high_voltage | |
jquery-rails | |
+ launchy | |
+ newrelic_rpm | |
+ paperclip | |
+ pg | |
rails (= 3.2.8) | |
+ rspec-rails (~> 2.9.0) | |
sass-rails (~> 3.2.3) | |
- sqlite3 | |
+ sham_rack | |
+ shoulda-matchers | |
+ therubyracer | |
+ thin | |
+ timecop | |
uglifier (>= 1.0.3) | |
diff --git a/Guardfile b/Guardfile | |
new file mode 100644 | |
index 0000000..eca0a25 | |
--- /dev/null | |
+++ b/Guardfile | |
@@ -0,0 +1,12 @@ | |
+guard 'spork' do | |
+ watch 'config/application.rb' | |
+ watch 'config/environment.rb' | |
+ watch %r{^config/environments/.*\.rb$} | |
+ watch %r{^config/initializers/.*\.rb$} | |
+ watch 'config/routes.rb' | |
+ watch 'Gemfile.lock' | |
+ watch 'spec/factories.rb' | |
+ watch 'spec/spec_helper.rb' | |
+ watch %r{^spec/support/.*\.rb$} | |
+ watch 'config/locales/.*' | |
+end | |
diff --git a/Procfile b/Procfile | |
new file mode 100644 | |
index 0000000..b41d8da | |
--- /dev/null | |
+++ b/Procfile | |
@@ -0,0 +1 @@ | |
+web: bundle exec rails server thin -p $PORT | |
diff --git a/README.md b/README.md | |
new file mode 100644 | |
index 0000000..a3a0d8d | |
--- /dev/null | |
+++ b/README.md | |
@@ -0,0 +1,404 @@ | |
+Style Guide | |
+=========== | |
+ | |
+A guide for programming in style. | |
+ | |
+Laptop setup | |
+------------ | |
+ | |
+Set up your laptop with [this script](https://github.com/thoughtbot/laptop) | |
+and [these dotfiles](https://github.com/thoughtbot/dotfiles). | |
+ | |
+Project setup | |
+------------- | |
+ | |
+Get the code. | |
+ | |
+ git clone git@github.com:organization/project.git | |
+ | |
+Set up the project's dependencies. | |
+ | |
+ cd project | |
+ bundle --binstubs | |
+ rake db:create | |
+ rake db:schema:load | |
+ rake db:seed | |
+ | |
+Add Heroku remotes for staging and production environments. | |
+ | |
+ git remote add staging git@heroku.com:<app>-staging.git | |
+ git remote add production git@heroku.com:<app>-production.git | |
+ | |
+Use [Heroku config](https://github.com/ddollar/heroku-config) to get `ENV` | |
+variables. | |
+ | |
+ heroku config:pull --app <app>-staging | |
+ | |
+Delete extra lines in `.env`, leaving only those needed for app to function | |
+properly. | |
+ | |
+ BRAINTREE_MERCHANT_ID | |
+ BRAINTREE_PRIVATE_KEY | |
+ BRAINTREE_PUBLIC_KEY | |
+ S3_KEY | |
+ S3_SECRET | |
+ | |
+Use [Foreman](http://goo.gl/oy4uw) to run the app locally. | |
+ | |
+ foreman start | |
+ | |
+It uses your `.env` file and `Procfile` to run processes just like Heroku's | |
+[Cedar](https://devcenter.heroku.com/articles/cedar/) stack. | |
+ | |
+Development | |
+----------- | |
+ | |
+Create a local feature branch based off master. | |
+ | |
+ git checkout master | |
+ git pull --rebase | |
+ git checkout -b feature-xyz | |
+ | |
+Rebase frequently to incorporate upstream changes. | |
+ | |
+ git fetch origin | |
+ git rebase origin/master | |
+ <resolve conflicts> | |
+ | |
+When feature is complete and tests pass, commit the changes. | |
+ | |
+ rake | |
+ git add -A | |
+ git status | |
+ git commit -v | |
+ | |
+Write a [good commit message](http://goo.gl/w11us). | |
+ | |
+ Present-tense summary under 50 characters | |
+ | |
+ * More information about commit (under 72 characters). | |
+ * More information about commit (under 72 characters). | |
+ | |
+Share your branch. | |
+ | |
+ git push origin [branch] | |
+ | |
+Submit a [Github pull request](http://goo.gl/Kmdee). | |
+ | |
+Ask for a code review in [Campfire](http://campfirenow.com). | |
+ | |
+Code review | |
+----------- | |
+ | |
+A team member other than the author reviews the pull request. | |
+ | |
+They make comments and ask questions directly on lines of code in the Github | |
+web interface or in Campfire. | |
+ | |
+For changes which they can make themselves, they check out the branch. | |
+ | |
+ git checkout <branch> | |
+ rake db:migrate | |
+ rake | |
+ git diff staging..HEAD | |
+ | |
+They make small changes right in the branch, test the feature in browser, | |
+run tests, commit, and push. | |
+ | |
+When satisfied, they comment on the pull request `Ready to squash and merge.` | |
+ | |
+Deploy | |
+------ | |
+ | |
+If there are multiple commits in the branch, squash them. | |
+ | |
+ git rebase -i staging/master | |
+ rake | |
+ | |
+View a list of new commits. View changed files. Merge branch into staging. | |
+ | |
+ git checkout staging | |
+ git fetch staging | |
+ git reset --hard staging/master | |
+ git log staging..[branch] | |
+ git diff --stat [branch] | |
+ git merge [branch] --ff-only | |
+ | |
+Deploy to [Heroku](https://devcenter.heroku.com/articles/quickstart). | |
+ | |
+ git push staging | |
+ | |
+Run migrations (if necessary). | |
+ | |
+ heroku run rake db:migrate --app <app> | |
+ | |
+Restart the dynos if migrations were run. | |
+ | |
+ heroku restart --app <app> | |
+ | |
+[Introspect](http://goo.gl/tTgVF) to make sure everything's ok. | |
+ | |
+ watch heroku ps --app <app> | |
+ | |
+Test the feature in browser. | |
+ | |
+Delete your remote feature branch. | |
+ | |
+ git push origin :[branch] | |
+ | |
+Delete your local feature branch. | |
+ | |
+ git branch -d [branch] | |
+ | |
+Close pull request and comment `Merged.` | |
+ | |
+Deploy to production. | |
+ | |
+ git checkout production | |
+ git fetch production | |
+ git reset --hard production/master | |
+ git log production..staging | |
+ git diff --stat staging/master | |
+ git merge staging --ff-only | |
+ git push production | |
+ heroku run rake db:migrate --app <app> | |
+ heroku restart --app <app> | |
+ watch heroku ps --app <app> | |
+ | |
+Watch logs and metrics dashboards. If the feature is working, merge into master. | |
+ | |
+ git checkout master | |
+ git fetch origin | |
+ git log production..master | |
+ git merge production --ff-only | |
+ git push origin master | |
+ | |
+Use scripts from [thoughtbot/dotfiles](http://github.com/thoughtbot/dotfiles) | |
+to quickly access the Heroku console, backup the production database, and | |
+transfer production data to staging. | |
+ | |
+Formatting | |
+---------- | |
+ | |
+* Delete trailing whitespace. | |
+* Don't include spaces after `(`, `[` or before `]`, `)`. | |
+* Don't vertically align tokens on consecutive lines. | |
+* Include spaces around infix method invocations like `+` and `-`. | |
+* Indent continued lines two spaces. | |
+* Indent private methods equal to public methods. | |
+* Limit lines to a maximum of 80 characters. | |
+* Use 2 space indentation (no tabs) unless otherwise noted. | |
+* Use an empty line between methods, blocks and conditionals. | |
+* Use spaces around operators, after commas, colons and semicolons, around `{` | |
+ and before `}`. | |
+ | |
+Naming | |
+------ | |
+ | |
+* Avoid abbreviations. | |
+* Avoid Hungarian notiation (`szName`). | |
+* Avoid types in names (`user_array`). | |
+* Name background jobs with a `Job` suffix. | |
+* Name the enumeration parameter the singular of the collection. | |
+* Name variables, methods, and classes to reveal intent. | |
+* Treat acronyms as words in names (`XmlHttpRequest` not `XMLHTTPRequest`), | |
+ even if the acronym is the entire name (`class Html` not `class HTML`). | |
+ | |
+Design | |
+------ | |
+ | |
+* Aggressively remove duplication during development. | |
+* Avoid comments. | |
+* Avoid global variables. | |
+* Avoid long parameter lists. | |
+* Be consistent. | |
+* Don't duplicate the functionality of a built-in library. | |
+* Don't swallow exceptions or "fail silently." | |
+* Don't write code that guesses at future functionality. | |
+* [Exceptions should be exceptional](http://rdd.me/yichhgvu). | |
+* [Keep the code simple](http://rdd.me/ko2aqda2). | |
+* Limit the number of collaborators of an object. | |
+* Prefer composition over inheritance. | |
+* Prefer small methods. One line is best. | |
+* Prefer small objects with a single, well-defined responsibility. | |
+* [Tell, don't ask](http://goo.gl/Ztawt). | |
+ | |
+Javascript | |
+---------- | |
+ | |
+* Define functions that operate on `window` or DOM in scope of `window`. | |
+* Initialize arrays using `[]`. | |
+* Initialize empty objects and hashes using `{}`. | |
+* Use `CamelCase` for prototypes, `mixedCase` for variables and functions, | |
+ `SCREAMING_SNAKE_CASE` for constants, `_single_leading_underscore` for | |
+ private variables and functions. | |
+* Use `data-` attributes to bind event handlers. | |
+* Use the [module pattern](http://goo.gl/JDtHN) to control method visibility. | |
+ | |
+Ruby | |
+---- | |
+ | |
+* Avoid conditional modifiers (lines that end with conditionals). | |
+* Avoid hashes as optional parameters. Does the method do too much? | |
+* Avoid including code and gems in source control that are specific to your | |
+ development machine or process. Examples: `.rvmrc`, `.swp` | |
+* Avoid meta-programming. | |
+* Avoid monkey-patching core classes. | |
+* Avoid ternary operators (`boolean ? true : false`). Use multi-line `if` | |
+ instead to emphasize code branches. | |
+* Define the project's [Ruby version in the | |
+ Gemfile](http://gembundler.com/man/gemfile.5.html#RUBY-ruby-). | |
+* Prefer classes to modules when designing functionality that is shared by | |
+ multiple models. | |
+* Prefer `detect`, not `find`, and `select`, not `find_all`, to avoid confusion | |
+ with ActiveRecord and keep `select`/`reject` symmetry. | |
+* Prefer `map`, not `collect`, and `reduce`, not `inject`, due to symmetry and | |
+ familarity with mapping and reducing in other technologies. | |
+* Use `_` for unused block parameters: `hash.map { |_, v| v + 1 }` | |
+* Use `%{}` for single-line strings needing interpolation and double-quotes. | |
+* Use `%w()`, not `['', '']`, for an array of words. | |
+* Use `&&` and `||` for boolean expressions. | |
+* Use `||=` freely. | |
+* Use `{...}`, not `do..end`, for single-line blocks. | |
+* Use `!` suffix for dangerous methods (modifies `self`). | |
+* Use `?` suffix for predicate methods (return a boolean). | |
+* Use `CamelCase` for classes and modules, `snake_case` for variables and | |
+ methods, `SCREAMING_SNAKE_CASE` for constants. | |
+* Use `def` with parentheses when there are arguments. | |
+* Use `do..end`, not `{...}`, for multi-line blocks. | |
+* Use `each`, not `for`, for iteration. | |
+* Use heredocs for multi-line strings. | |
+* Use `/(?:first|second)/`, not `/(first|second)/`, when you don't need the | |
+ captured group. | |
+* Use `private`, not `protected`, to indicate scope. | |
+* Use `def self.method`, not `def Class.method` or `class << self`. | |
+* Use `Set`, not `Array`, for arrays with unique elements. The lookup is faster. | |
+* Use single-quotes for strings unless interpolating. | |
+ | |
+Rails | |
+----- | |
+ | |
+* Avoid the `:except` option in routes. | |
+* Avoid `member` and `collection` routes. | |
+* Avoid Single Table Inheritance. | |
+* Don't change a migration after it has been committed unless it cannot be | |
+ solved with another migration. | |
+* Don't invoke a model's class directly from a view. | |
+* Don't use SQL or SQL fragments (`where('inviter_id is not null')`) outside of | |
+ models. | |
+* Keep the `db/schema.rb` under version control. | |
+* Limit the number of instance variables shared between controller and view. | |
+* Name initializers for their gem name. Example: `paperclip.rb` | |
+* Order controller contents: filters, public methods, private methods. | |
+* Order model contents: constants, attributes, associations, nested attributes, | |
+ named scopes, validations, callbacks, public methods, private methods. | |
+* Prefer [decorators](http://goo.gl/yeF3X), not view helpers. | |
+* Put all copy text in models, views, controllers, and mailers in | |
+ `config/locales`. | |
+* Set `config.assets.initialize_on_precompile = false` in | |
+ `config/application.rb`. | |
+* Set default values in the database. | |
+* Use `_path`, not `_url`, for named routes everywhere except mailer views. | |
+* Use `def self.method`, not the `named_scope :method` DSL. | |
+* Use `I18n.t 'dot.separated.key'`, not `I18n.t :key, | |
+ :scope => [:dot, :separated]`. | |
+* Use `has_and_belongs_to_many` if all you need is a join table. Do not include | |
+ an `id` or timestamps. | |
+* Use namespaced locale lookup in views by prefixing a period: `t '.title'`. | |
+* Use nested routes to express `belongs_to` relationships between resources. | |
+* Use SQL, not `ActiveRecord` models, in migrations. | |
+* Use the default `render 'partial'` syntax over `render partial: 'partial'`. | |
+* Use the `:only` option to explicitly state exposed routes. | |
+ | |
+Database | |
+-------- | |
+ | |
+* Avoid multicolumn indexes in Postgres. It [combines multiple | |
+ indexes](http://goo.gl/pY3Po) efficiently. | |
+* Create [indexes concurrently](https://gist.github.com/3186117) to avoid table | |
+ locks and [reduced performance](http://goo.gl/fi5ER) during deploys. | |
+* Consider a [partial index](http://goo.gl/YC8Jt) for queries on booleans. | |
+* Constrain most columns as [`NOT NULL`](http://goo.gl/0GeBr). | |
+* Create a read-only [Heroku Follower](http://goo.gl/xWDMx) for your | |
+ production database. If a Heroku database outage occurs, Heroku can use the | |
+ follower to get your app back up and running faster. | |
+* Index all foreign keys. | |
+* Use a Heroku Follower database for analytics to limit reads on the primary | |
+ database. | |
+ | |
+Background Jobs | |
+--------------- | |
+ | |
+* Define a `PRIORITY` constant at the top of the class. | |
+* Define two public methods: `self.enqueue` and `perform`. | |
+* Enqueue the job in `self.enqueue` [like this](http://goo.gl/C7e54). | |
+* Put background jobs in `app/jobs`. | |
+* Store IDs, not `ActiveRecord` objects for cleaner serialization, then re-find | |
+ the `ActiveRecord` object in the `perform` method. | |
+* Subclass the job from `Struct.new(:something_id)`. | |
+* Use [`Delayed::Job`](http://goo.gl/sRYju) for background jobs. | |
+ | |
+----- | |
+ | |
+* Set `config.action_mailer.raise_delivery_errors = true` in the development | |
+ environment. | |
+* Set `config.action_mailer.delivery_method = :test` in the test environment. | |
+* Use one `ActionMailer` for the app. Name it `Mailer`. | |
+* Use [SendGrid](http://goo.gl/Kxu9W) or [Amazon SES](http://goo.gl/A5jAA) to | |
+ deliver email in staging and production environments. | |
+* Use [single recipient SMTP](http://goo.gl/FWdhG) in staging environment. | |
+* Use the user's name in the `From` header and email in the `Reply-To` when | |
+ [delivering email on behalf of the app's users](http://goo.gl/5w1ck). | |
+ | |
+Gems | |
+---- | |
+ | |
+* Use [AssetSync](http://goo.gl/m58tF) to serve assets from S3. | |
+* Use [Bourbon](http://goo.gl/wpyee) for Sass mixins. | |
+* Use [Bourne](http://goo.gl/lE7zH) for stubs and spies. | |
+* Use [Braintree](http://goo.gl/mpWTp) for credit card processing. | |
+* Use [Clearance](http://goo.gl/svPGo) for authentication. | |
+* Use [Factory Girl](http://goo.gl/AB8bI) to set up test data. | |
+* Use [Geocoder](http://goo.gl/CKnYF) for geocoding. | |
+* Use [Haml](http://haml.info) for view templates. | |
+* Use [Money](http://goo.gl/2CNfc) for money objects. | |
+* Use [New Relic](http://goo.gl/F7Q56) for performance monitoring. | |
+* Use [Paperclip](http://goo.gl/eSESD) for file uploads. | |
+* Use [Thin](http://goo.gl/5Hlr) for serving web requests. | |
+* Use [WebMock](http://goo.gl/BC1Ac) to disable real HTTP requests. | |
+ | |
+Testing | |
+------- | |
+ | |
+* Avoid `its`, `let`, `let!`, `specify`, `subject`, and other DSLs. Prefer | |
+ explicitness and consistency. | |
+* Disable real HTTP requests to external services with | |
+ `WebMock.disable_net_connect!`. | |
+* Don't prefix `it` blocks with 'should'. | |
+* Name outer `describe` blocks after the method under test. Use `.method` | |
+ for class methods and `#method` for instance methods. | |
+* Order factories.rb: sequences, traits, factory definitions. | |
+* Order factory definitions alphabetically by factory name. | |
+* Order factory attributes: implicit attributes, newline, explicit attributes, | |
+ child factory definitions. Each section's attributes are alphabetical. | |
+* Prefix `context` blocks names with 'given' when receiving input. Prefix with | |
+ 'when' in most other cases. | |
+* Run specs with `--format documentation`. | |
+* Test background jobs with a [`Delayed::Job` matcher](http://goo.gl/bzBlN). | |
+* Use a `context` block for each execution path through the method. | |
+* Use a [Fake](http://goo.gl/YR7Hh) to stub requests to external services. | |
+* Use a `before` block to define phases of [Four Phase | |
+ Test](http://goo.gl/J9FiJ). | |
+* Use integration tests to execute the entire app. | |
+* Use non-[SUT](http://goo.gl/r5Ti2) methods in expectations when possible. | |
+* Use one expectation per `it` block. | |
+* Use [stubs and spies](http://goo.gl/EciDJ) (not mocks) in isolated tests. | |
+ | |
+Browsers | |
+-------- | |
+ | |
+* Don't support clients without Javascript. | |
+* Don't support IE6. | |
+ | |
+[Always be learning](http://learn.thoughtbot.com). | |
diff --git a/README.rdoc b/README.rdoc | |
deleted file mode 100644 | |
index 7c36f23..0000000 | |
--- a/README.rdoc | |
+++ /dev/null | |
@@ -1,261 +0,0 @@ | |
-== Welcome to Rails | |
- | |
-Rails is a web-application framework that includes everything needed to create | |
-database-backed web applications according to the Model-View-Control pattern. | |
- | |
-This pattern splits the view (also called the presentation) into "dumb" | |
-templates that are primarily responsible for inserting pre-built data in between | |
-HTML tags. The model contains the "smart" domain objects (such as Account, | |
-Product, Person, Post) that holds all the business logic and knows how to | |
-persist themselves to a database. The controller handles the incoming requests | |
-(such as Save New Account, Update Product, Show Post) by manipulating the model | |
-and directing data to the view. | |
- | |
-In Rails, the model is handled by what's called an object-relational mapping | |
-layer entitled Active Record. This layer allows you to present the data from | |
-database rows as objects and embellish these data objects with business logic | |
-methods. You can read more about Active Record in | |
-link:files/vendor/rails/activerecord/README.html. | |
- | |
-The controller and view are handled by the Action Pack, which handles both | |
-layers by its two parts: Action View and Action Controller. These two layers | |
-are bundled in a single package due to their heavy interdependence. This is | |
-unlike the relationship between the Active Record and Action Pack that is much | |
-more separate. Each of these packages can be used independently outside of | |
-Rails. You can read more about Action Pack in | |
-link:files/vendor/rails/actionpack/README.html. | |
- | |
- | |
-== Getting Started | |
- | |
-1. At the command prompt, create a new Rails application: | |
- <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name) | |
- | |
-2. Change directory to <tt>myapp</tt> and start the web server: | |
- <tt>cd myapp; rails server</tt> (run with --help for options) | |
- | |
-3. Go to http://localhost:3000/ and you'll see: | |
- "Welcome aboard: You're riding Ruby on Rails!" | |
- | |
-4. Follow the guidelines to start developing your application. You can find | |
-the following resources handy: | |
- | |
-* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html | |
-* Ruby on Rails Tutorial Book: http://www.railstutorial.org/ | |
- | |
- | |
-== Debugging Rails | |
- | |
-Sometimes your application goes wrong. Fortunately there are a lot of tools that | |
-will help you debug it and get it back on the rails. | |
- | |
-First area to check is the application log files. Have "tail -f" commands | |
-running on the server.log and development.log. Rails will automatically display | |
-debugging and runtime information to these files. Debugging info will also be | |
-shown in the browser on requests from 127.0.0.1. | |
- | |
-You can also log your own messages directly into the log file from your code | |
-using the Ruby logger class from inside your controllers. Example: | |
- | |
- class WeblogController < ActionController::Base | |
- def destroy | |
- @weblog = Weblog.find(params[:id]) | |
- @weblog.destroy | |
- logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") | |
- end | |
- end | |
- | |
-The result will be a message in your log file along the lines of: | |
- | |
- Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! | |
- | |
-More information on how to use the logger is at http://www.ruby-doc.org/core/ | |
- | |
-Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are | |
-several books available online as well: | |
- | |
-* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) | |
-* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) | |
- | |
-These two books will bring you up to speed on the Ruby language and also on | |
-programming in general. | |
- | |
- | |
-== Debugger | |
- | |
-Debugger support is available through the debugger command when you start your | |
-Mongrel or WEBrick server with --debugger. This means that you can break out of | |
-execution at any point in the code, investigate and change the model, and then, | |
-resume execution! You need to install ruby-debug to run the server in debugging | |
-mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example: | |
- | |
- class WeblogController < ActionController::Base | |
- def index | |
- @posts = Post.all | |
- debugger | |
- end | |
- end | |
- | |
-So the controller will accept the action, run the first line, then present you | |
-with a IRB prompt in the server window. Here you can do things like: | |
- | |
- >> @posts.inspect | |
- => "[#<Post:0x14a6be8 | |
- @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>, | |
- #<Post:0x14a6620 | |
- @attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]" | |
- >> @posts.first.title = "hello from a debugger" | |
- => "hello from a debugger" | |
- | |
-...and even better, you can examine how your runtime objects actually work: | |
- | |
- >> f = @posts.first | |
- => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}> | |
- >> f. | |
- Display all 152 possibilities? (y or n) | |
- | |
-Finally, when you're ready to resume execution, you can enter "cont". | |
- | |
- | |
-== Console | |
- | |
-The console is a Ruby shell, which allows you to interact with your | |
-application's domain model. Here you'll have all parts of the application | |
-configured, just like it is when the application is running. You can inspect | |
-domain models, change values, and save to the database. Starting the script | |
-without arguments will launch it in the development environment. | |
- | |
-To start the console, run <tt>rails console</tt> from the application | |
-directory. | |
- | |
-Options: | |
- | |
-* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications | |
- made to the database. | |
-* Passing an environment name as an argument will load the corresponding | |
- environment. Example: <tt>rails console production</tt>. | |
- | |
-To reload your controllers and models after launching the console run | |
-<tt>reload!</tt> | |
- | |
-More information about irb can be found at: | |
-link:http://www.rubycentral.org/pickaxe/irb.html | |
- | |
- | |
-== dbconsole | |
- | |
-You can go to the command line of your database directly through <tt>rails | |
-dbconsole</tt>. You would be connected to the database with the credentials | |
-defined in database.yml. Starting the script without arguments will connect you | |
-to the development database. Passing an argument will connect you to a different | |
-database, like <tt>rails dbconsole production</tt>. Currently works for MySQL, | |
-PostgreSQL and SQLite 3. | |
- | |
-== Description of Contents | |
- | |
-The default directory structure of a generated Ruby on Rails application: | |
- | |
- |-- app | |
- | |-- assets | |
- | |-- images | |
- | |-- javascripts | |
- | `-- stylesheets | |
- | |-- controllers | |
- | |-- helpers | |
- | |-- mailers | |
- | |-- models | |
- | `-- views | |
- | `-- layouts | |
- |-- config | |
- | |-- environments | |
- | |-- initializers | |
- | `-- locales | |
- |-- db | |
- |-- doc | |
- |-- lib | |
- | `-- tasks | |
- |-- log | |
- |-- public | |
- |-- script | |
- |-- test | |
- | |-- fixtures | |
- | |-- functional | |
- | |-- integration | |
- | |-- performance | |
- | `-- unit | |
- |-- tmp | |
- | |-- cache | |
- | |-- pids | |
- | |-- sessions | |
- | `-- sockets | |
- `-- vendor | |
- |-- assets | |
- `-- stylesheets | |
- `-- plugins | |
- | |
-app | |
- Holds all the code that's specific to this particular application. | |
- | |
-app/assets | |
- Contains subdirectories for images, stylesheets, and JavaScript files. | |
- | |
-app/controllers | |
- Holds controllers that should be named like weblogs_controller.rb for | |
- automated URL mapping. All controllers should descend from | |
- ApplicationController which itself descends from ActionController::Base. | |
- | |
-app/models | |
- Holds models that should be named like post.rb. Models descend from | |
- ActiveRecord::Base by default. | |
- | |
-app/views | |
- Holds the template files for the view that should be named like | |
- weblogs/index.html.erb for the WeblogsController#index action. All views use | |
- eRuby syntax by default. | |
- | |
-app/views/layouts | |
- Holds the template files for layouts to be used with views. This models the | |
- common header/footer method of wrapping views. In your views, define a layout | |
- using the <tt>layout :default</tt> and create a file named default.html.erb. | |
- Inside default.html.erb, call <% yield %> to render the view using this | |
- layout. | |
- | |
-app/helpers | |
- Holds view helpers that should be named like weblogs_helper.rb. These are | |
- generated for you automatically when using generators for controllers. | |
- Helpers can be used to wrap functionality for your views into methods. | |
- | |
-config | |
- Configuration files for the Rails environment, the routing map, the database, | |
- and other dependencies. | |
- | |
-db | |
- Contains the database schema in schema.rb. db/migrate contains all the | |
- sequence of Migrations for your schema. | |
- | |
-doc | |
- This directory is where your application documentation will be stored when | |
- generated using <tt>rake doc:app</tt> | |
- | |
-lib | |
- Application specific libraries. Basically, any kind of custom code that | |
- doesn't belong under controllers, models, or helpers. This directory is in | |
- the load path. | |
- | |
-public | |
- The directory available for the web server. Also contains the dispatchers and the | |
- default HTML files. This should be set as the DOCUMENT_ROOT of your web | |
- server. | |
- | |
-script | |
- Helper scripts for automation and generation. | |
- | |
-test | |
- Unit and functional tests along with fixtures. When using the rails generate | |
- command, template test files will be generated for you and placed in this | |
- directory. | |
- | |
-vendor | |
- External libraries that the application depends on. Also includes the plugins | |
- subdirectory. If the app has frozen rails, those gems also go here, under | |
- vendor/rails/. This directory is in the load path. | |
diff --git a/Rakefile b/Rakefile | |
index b2d78e7..4c794f4 100644 | |
--- a/Rakefile | |
+++ b/Rakefile | |
@@ -5,3 +5,5 @@ | |
require File.expand_path('../config/application', __FILE__) | |
DemoApp::Application.load_tasks | |
+task(:default).clear | |
+task :default => [:spec, :cucumber] | |
\ No newline at end of file | |
diff --git a/app/assets/images/.gitkeep b/app/assets/images/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/app/assets/images/rails.png b/app/assets/images/rails.png | |
deleted file mode 100644 | |
index d5edc04..0000000 | |
Binary files a/app/assets/images/rails.png and /dev/null differ | |
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js | |
index 9097d83..1dc449f 100644 | |
--- a/app/assets/javascripts/application.js | |
+++ b/app/assets/javascripts/application.js | |
@@ -12,4 +12,5 @@ | |
// | |
//= require jquery | |
//= require jquery_ujs | |
+//= require jquery-ui | |
//= require_tree . | |
diff --git a/app/assets/javascripts/prefilled_input.js b/app/assets/javascripts/prefilled_input.js | |
new file mode 100644 | |
index 0000000..e1153cf | |
--- /dev/null | |
+++ b/app/assets/javascripts/prefilled_input.js | |
@@ -0,0 +1,59 @@ | |
+// clear inputs with starter values | |
+new function($) { | |
+ $.fn.prefilledInput = function() { | |
+ | |
+ var focus = function () { | |
+ $(this).removeClass('prefilled'); | |
+ if (this.value == this.prefilledValue) { | |
+ this.value = ''; | |
+ } | |
+ }; | |
+ | |
+ var blur = function () { | |
+ if (this.value == '') { | |
+ $(this).addClass('prefilled').val(this.prefilledValue); | |
+ } else if (this.value != this.prefilledValue) { | |
+ $(this).removeClass('prefilled'); | |
+ } | |
+ }; | |
+ | |
+ var extractPrefilledValue = function () { | |
+ if (this.title) { | |
+ this.prefilledValue = this.title; | |
+ this.title = ''; | |
+ } else if (this.id) { | |
+ this.prefilledValue = $('label[for=' + this.id + ']').hide().text(); | |
+ } | |
+ if (this.prefilledValue) { | |
+ this.prefilledValue = this.prefilledValue.replace(/\*$/, ''); | |
+ } | |
+ }; | |
+ | |
+ var initialize = function (index) { | |
+ if (!this.prefilledValue) { | |
+ this.extractPrefilledValue = extractPrefilledValue; | |
+ this.extractPrefilledValue(); | |
+ $(this).trigger('blur'); | |
+ } | |
+ }; | |
+ | |
+ return this.filter(":input"). | |
+ focus(focus). | |
+ blur(blur). | |
+ each(initialize); | |
+ }; | |
+ | |
+ var clearPrefilledInputs = function () { | |
+ var form = this.form || this; | |
+ $(form).find("input.prefilled, textarea.prefilled").val(""); | |
+ }; | |
+ | |
+ var prefilledSetup = function () { | |
+ $('input.prefilled, textarea.prefilled').prefilledInput(); | |
+ $('form').submit(clearPrefilledInputs); | |
+ $('input:submit, button:submit').click(clearPrefilledInputs); | |
+ }; | |
+ | |
+ $(document).ready(prefilledSetup); | |
+ $(document).ajaxComplete(prefilledSetup); | |
+}(jQuery); | |
diff --git a/app/assets/stylesheets/_screen.scss b/app/assets/stylesheets/_screen.scss | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css | |
deleted file mode 100644 | |
index 3192ec8..0000000 | |
--- a/app/assets/stylesheets/application.css | |
+++ /dev/null | |
@@ -1,13 +0,0 @@ | |
-/* | |
- * This is a manifest file that'll be compiled into application.css, which will include all the files | |
- * listed below. | |
- * | |
- * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, | |
- * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. | |
- * | |
- * You're free to add application-wide styles to this file and they'll appear at the top of the | |
- * compiled file, but it's generally better to create a new file per style scope. | |
- * | |
- *= require_self | |
- *= require_tree . | |
- */ | |
diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss | |
new file mode 100644 | |
index 0000000..9b644a9 | |
--- /dev/null | |
+++ b/app/assets/stylesheets/application.css.scss | |
@@ -0,0 +1,17 @@ | |
+/* | |
+ * This is a manifest file that'll be compiled into application.css, which will include all the files | |
+ * listed below. | |
+ * | |
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, | |
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. | |
+ * | |
+ * You're free to add application-wide styles to this file and they'll appear at the top of the | |
+ * compiled file, but it's generally better to create a new file per style scope. | |
+ * | |
+ *= require_self | |
+ *= require_tree . | |
+ */ | |
+ | |
+ | |
+@import 'flutie'; | |
+@import 'bourbon'; | |
\ No newline at end of file | |
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb | |
index e8065d9..f8a344b 100644 | |
--- a/app/controllers/application_controller.rb | |
+++ b/app/controllers/application_controller.rb | |
@@ -1,3 +1,4 @@ | |
class ApplicationController < ActionController::Base | |
+ include Clearance::Authentication | |
protect_from_forgery | |
end | |
diff --git a/app/models/user.rb b/app/models/user.rb | |
new file mode 100644 | |
index 0000000..e7bd019 | |
--- /dev/null | |
+++ b/app/models/user.rb | |
@@ -0,0 +1,4 @@ | |
+class User < ActiveRecord::Base | |
+ include Clearance::User | |
+ attr_accessible :email, :password | |
+end | |
diff --git a/app/validators/email_validator.rb b/app/validators/email_validator.rb | |
new file mode 100644 | |
index 0000000..676a654 | |
--- /dev/null | |
+++ b/app/validators/email_validator.rb | |
@@ -0,0 +1,7 @@ | |
+class EmailValidator < ActiveModel::EachValidator | |
+ def validate_each(record, attribute, value) | |
+ unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i | |
+ record.errors[attribute] << (options[:message] || "is not an email") | |
+ end | |
+ end | |
+end | |
diff --git a/app/views/application/_flashes.html.erb b/app/views/application/_flashes.html.erb | |
new file mode 100644 | |
index 0000000..ae7ff75 | |
--- /dev/null | |
+++ b/app/views/application/_flashes.html.erb | |
@@ -0,0 +1,5 @@ | |
+<div id="flash"> | |
+ <% flash.each do |key, value| -%> | |
+ <div id="flash_<%= key %>"><%= value %></div> | |
+ <% end -%> | |
+</div> | |
diff --git a/app/views/application/_javascript.html.erb b/app/views/application/_javascript.html.erb | |
new file mode 100644 | |
index 0000000..a5fa70a | |
--- /dev/null | |
+++ b/app/views/application/_javascript.html.erb | |
@@ -0,0 +1,9 @@ | |
+<%= javascript_include_tag :application %> | |
+ | |
+<%= yield :javascript %> | |
+ | |
+<% if Rails.env.test? %> | |
+ <%= javascript_tag do %> | |
+ $.ajaxSetup({ async: false }); | |
+ <% end %> | |
+<% end %> | |
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb | |
index c15e160..994c7b6 100644 | |
--- a/app/views/layouts/application.html.erb | |
+++ b/app/views/layouts/application.html.erb | |
@@ -1,14 +1,22 @@ | |
<!DOCTYPE html> | |
<html> | |
<head> | |
- <title>DemoApp</title> | |
- <%= stylesheet_link_tag "application", :media => "all" %> | |
- <%= javascript_include_tag "application" %> | |
+ <meta charset="utf-8" /> | |
+ <meta name="ROBOTS" content="NOODP" /> | |
+ <title><%= page_title %></title> | |
+ <%= stylesheet_link_tag :application, :media => 'all' %> | |
<%= csrf_meta_tags %> | |
</head> | |
-<body> | |
- | |
-<%= yield %> | |
- | |
+<body class="<%= body_class %>"> | |
+ <header> | |
+ <% if signed_in? -%> | |
+ <%= link_to "Sign out", sign_out_path, :method => :delete %> | |
+ <% else -%> | |
+ <%= link_to "Sign in", sign_in_path %> | |
+ <% end -%> | |
+ </header> | |
+ <%= render 'flashes' -%> | |
+ <%= yield %> | |
+ <%= render 'javascript' %> | |
</body> | |
</html> | |
diff --git a/app/views/pages/.gitkeep b/app/views/pages/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/config/application.rb b/config/application.rb | |
index 5f91dbc..37cb118 100644 | |
--- a/config/application.rb | |
+++ b/config/application.rb | |
@@ -1,6 +1,12 @@ | |
require File.expand_path('../boot', __FILE__) | |
-require 'rails/all' | |
+# Pick the frameworks you want: | |
+require "active_record/railtie" | |
+require "action_controller/railtie" | |
+require "action_mailer/railtie" | |
+require "active_resource/railtie" | |
+require "sprockets/railtie" | |
+# require "rails/test_unit/railtie" | |
if defined?(Bundler) | |
# If you precompile assets before deploying to production, use this line | |
@@ -11,6 +17,14 @@ end | |
module DemoApp | |
class Application < Rails::Application | |
+ config.active_record.default_timezone = :utc | |
+ config.generators do |generate| | |
+ generate.test_framework :rspec | |
+ generate.helper false | |
+ generate.stylesheets false | |
+ generate.javascript_engine false | |
+ generate.view_specs false | |
+ end | |
# Settings in config/environments/* take precedence over those specified here. | |
# Application configuration should go into files in config/initializers | |
# -- all .rb files in that directory are automatically loaded. | |
@@ -55,6 +69,7 @@ module DemoApp | |
# Enable the asset pipeline | |
config.assets.enabled = true | |
+ config.assets.initialize_on_precompile = false | |
# Version of your assets, change this if you want to expire all your assets | |
config.assets.version = '1.0' | |
diff --git a/config/cucumber.yml b/config/cucumber.yml | |
new file mode 100644 | |
index 0000000..0941e46 | |
--- /dev/null | |
+++ b/config/cucumber.yml | |
@@ -0,0 +1,8 @@ | |
+<% | |
+rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" | |
+rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" | |
+std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip" | |
+%> | |
+default: <%= std_opts %> features -drb -r features | |
+wip: --tags @wip:3 --wip features | |
+rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip | |
diff --git a/config/database.yml b/config/database.yml | |
index 51a4dd4..7714782 100644 | |
--- a/config/database.yml | |
+++ b/config/database.yml | |
@@ -1,25 +1,13 @@ | |
-# SQLite version 3.x | |
-# gem install sqlite3 | |
-# | |
-# Ensure the SQLite 3 gem is defined in your Gemfile | |
-# gem 'sqlite3' | |
-development: | |
- adapter: sqlite3 | |
- database: db/development.sqlite3 | |
+development: &default | |
+ adapter: postgresql | |
+ database: demo-app_development | |
pool: 5 | |
timeout: 5000 | |
-# Warning: The database defined as "test" will be erased and | |
-# re-generated from your development database when you run "rake". | |
-# Do not set this db to the same as development or production. | |
-test: | |
- adapter: sqlite3 | |
- database: db/test.sqlite3 | |
- pool: 5 | |
- timeout: 5000 | |
+test: &test | |
+ <<: *default | |
+ database: demo-app_test | |
+ min_messages: warning | |
-production: | |
- adapter: sqlite3 | |
- database: db/production.sqlite3 | |
- pool: 5 | |
- timeout: 5000 | |
+cucumber: | |
+ <<: *test | |
\ No newline at end of file | |
diff --git a/config/environments/development.rb b/config/environments/development.rb | |
index 33676f2..0d87aec 100644 | |
--- a/config/environments/development.rb | |
+++ b/config/environments/development.rb | |
@@ -14,7 +14,7 @@ DemoApp::Application.configure do | |
config.action_controller.perform_caching = false | |
# Don't care if the mailer can't send | |
- config.action_mailer.raise_delivery_errors = false | |
+ config.action_mailer.raise_delivery_errors = true | |
# Print deprecation notices to the Rails logger | |
config.active_support.deprecation = :log | |
@@ -34,4 +34,6 @@ DemoApp::Application.configure do | |
# Expands the lines which load the assets | |
config.assets.debug = true | |
+ | |
+ config.action_mailer.default_url_options = { :host => 'demo-app.local' } | |
end | |
diff --git a/config/environments/production.rb b/config/environments/production.rb | |
index badcf19..5fc7f40 100644 | |
--- a/config/environments/production.rb | |
+++ b/config/environments/production.rb | |
@@ -64,4 +64,6 @@ DemoApp::Application.configure do | |
# Log the query plan for queries taking more than this (works | |
# with SQLite, MySQL, and PostgreSQL) | |
# config.active_record.auto_explain_threshold_in_seconds = 0.5 | |
+ | |
+ config.action_mailer.default_url_options = { :host => 'demo-app.com' } | |
end | |
diff --git a/config/environments/staging.rb b/config/environments/staging.rb | |
new file mode 100644 | |
index 0000000..24fd369 | |
--- /dev/null | |
+++ b/config/environments/staging.rb | |
@@ -0,0 +1,69 @@ | |
+DemoApp::Application.configure do | |
+ # Settings specified here will take precedence over those in config/application.rb | |
+ | |
+ # Code is not reloaded between requests | |
+ config.cache_classes = true | |
+ | |
+ # Full error reports are disabled and caching is turned on | |
+ config.consider_all_requests_local = false | |
+ config.action_controller.perform_caching = true | |
+ | |
+ # Disable Rails's static asset server (Apache or nginx will already do this) | |
+ config.serve_static_assets = false | |
+ | |
+ # Compress JavaScripts and CSS | |
+ config.assets.compress = true | |
+ | |
+ # Don't fallback to assets pipeline if a precompiled asset is missed | |
+ config.assets.compile = false | |
+ | |
+ # Generate digests for assets URLs | |
+ config.assets.digest = true | |
+ | |
+ # Defaults to nil and saved in location specified by config.assets.prefix | |
+ # config.assets.manifest = YOUR_PATH | |
+ | |
+ # Specifies the header that your server uses for sending files | |
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache | |
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx | |
+ | |
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. | |
+ # config.force_ssl = true | |
+ | |
+ # See everything in the log (default is :info) | |
+ # config.log_level = :debug | |
+ | |
+ # Prepend all log lines with the following tags | |
+ # config.log_tags = [ :subdomain, :uuid ] | |
+ | |
+ # Use a different logger for distributed setups | |
+ # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) | |
+ | |
+ # Use a different cache store in production | |
+ # config.cache_store = :mem_cache_store | |
+ | |
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server | |
+ # config.action_controller.asset_host = "http://assets.example.com" | |
+ | |
+ # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) | |
+ # config.assets.precompile += %w( search.js ) | |
+ | |
+ # Disable delivery errors, bad email addresses will be ignored | |
+ # config.action_mailer.raise_delivery_errors = false | |
+ | |
+ # Enable threaded mode | |
+ # config.threadsafe! | |
+ | |
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to | |
+ # the I18n.default_locale when a translation can not be found) | |
+ config.i18n.fallbacks = true | |
+ | |
+ # Send deprecation notices to registered listeners | |
+ config.active_support.deprecation = :notify | |
+ | |
+ # Log the query plan for queries taking more than this (works | |
+ # with SQLite, MySQL, and PostgreSQL) | |
+ # config.active_record.auto_explain_threshold_in_seconds = 0.5 | |
+ | |
+ config.action_mailer.default_url_options = { :host => 'staging.demo-app.com' } | |
+end | |
diff --git a/config/environments/test.rb b/config/environments/test.rb | |
index 9b2cd20..a1ac931 100644 | |
--- a/config/environments/test.rb | |
+++ b/config/environments/test.rb | |
@@ -34,4 +34,6 @@ DemoApp::Application.configure do | |
# Print deprecation notices to the stderr | |
config.active_support.deprecation = :stderr | |
+ | |
+ config.action_mailer.default_url_options = { :host => 'example.com' } | |
end | |
diff --git a/config/initializers/clearance.rb b/config/initializers/clearance.rb | |
new file mode 100644 | |
index 0000000..f0490ce | |
--- /dev/null | |
+++ b/config/initializers/clearance.rb | |
@@ -0,0 +1,3 @@ | |
+Clearance.configure do |config| | |
+ config.mailer_sender = 'reply@example.com' | |
+end | |
diff --git a/config/initializers/errors.rb b/config/initializers/errors.rb | |
new file mode 100644 | |
index 0000000..7b28e97 | |
--- /dev/null | |
+++ b/config/initializers/errors.rb | |
@@ -0,0 +1,28 @@ | |
+require 'net/http' | |
+require 'net/smtp' | |
+ | |
+# Example: | |
+# begin | |
+# some http call | |
+# rescue *HTTP_ERRORS => error | |
+# notify_hoptoad error | |
+# end | |
+ | |
+HTTP_ERRORS = [Timeout::Error, | |
+ Errno::EINVAL, | |
+ Errno::ECONNRESET, | |
+ EOFError, | |
+ Net::HTTPBadResponse, | |
+ Net::HTTPHeaderSyntaxError, | |
+ Net::ProtocolError] | |
+ | |
+SMTP_SERVER_ERRORS = [TimeoutError, | |
+ IOError, | |
+ Net::SMTPUnknownError, | |
+ Net::SMTPServerBusy, | |
+ Net::SMTPAuthenticationError] | |
+ | |
+SMTP_CLIENT_ERRORS = [Net::SMTPFatalError, | |
+ Net::SMTPSyntaxError] | |
+ | |
+SMTP_ERRORS = SMTP_SERVER_ERRORS + SMTP_CLIENT_ERRORS | |
diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb | |
index e73baed..0853f0c 100644 | |
--- a/config/initializers/secret_token.rb | |
+++ b/config/initializers/secret_token.rb | |
@@ -4,4 +4,4 @@ | |
# If you change this key, all old signed cookies will become invalid! | |
# Make sure the secret is at least 30 characters and all random, | |
# no regular words or you'll be exposed to dictionary attacks. | |
-DemoApp::Application.config.secret_token = 'f0f5527c8e636cab11af3ee3a3b63b7e171c36f042f88d96a2a8e8e7397065705d4e6f1b40e4aa6b0e1e875a964261fcd2ecfc94eda8c719322a30a26f9dd7ef' | |
+DemoApp::Application.config.secret_token = 'c56d2c8ee7590e6bdf813c4a1c0c9b4a3c2babf88f63c45c25848a4445def2c5149e32f5739e13c844a6e93186fd2ceb4321248746116106f1fb6e5becc7eb90' | |
diff --git a/config/initializers/time_formats.rb b/config/initializers/time_formats.rb | |
new file mode 100644 | |
index 0000000..a57a761 | |
--- /dev/null | |
+++ b/config/initializers/time_formats.rb | |
@@ -0,0 +1,6 @@ | |
+# { | |
+# :short_date => "%x", # 04/13/10 | |
+# :long_date => "%a, %b %d, %Y" # Tue, Apr 13, 2010 | |
+# }.each do |format_name, format_string| | |
+# Time::DATE_FORMATS[format_name] = format_string | |
+# end | |
diff --git a/config/routes.rb b/config/routes.rb | |
index da61cfc..ba9c1c7 100644 | |
--- a/config/routes.rb | |
+++ b/config/routes.rb | |
@@ -1,58 +1,4 @@ | |
DemoApp::Application.routes.draw do | |
- # The priority is based upon order of creation: | |
- # first created -> highest priority. | |
+ root :to => 'Clearance::Sessions#new' | |
- # Sample of regular route: | |
- # match 'products/:id' => 'catalog#view' | |
- # Keep in mind you can assign values other than :controller and :action | |
- | |
- # Sample of named route: | |
- # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase | |
- # This route can be invoked with purchase_url(:id => product.id) | |
- | |
- # Sample resource route (maps HTTP verbs to controller actions automatically): | |
- # resources :products | |
- | |
- # Sample resource route with options: | |
- # resources :products do | |
- # member do | |
- # get 'short' | |
- # post 'toggle' | |
- # end | |
- # | |
- # collection do | |
- # get 'sold' | |
- # end | |
- # end | |
- | |
- # Sample resource route with sub-resources: | |
- # resources :products do | |
- # resources :comments, :sales | |
- # resource :seller | |
- # end | |
- | |
- # Sample resource route with more complex sub-resources | |
- # resources :products do | |
- # resources :comments | |
- # resources :sales do | |
- # get 'recent', :on => :collection | |
- # end | |
- # end | |
- | |
- # Sample resource route within a namespace: | |
- # namespace :admin do | |
- # # Directs /admin/products/* to Admin::ProductsController | |
- # # (app/controllers/admin/products_controller.rb) | |
- # resources :products | |
- # end | |
- | |
- # You can have the root of your site routed with "root" | |
- # just remember to delete public/index.html. | |
- # root :to => 'welcome#index' | |
- | |
- # See how all your routes lay out with "rake routes" | |
- | |
- # This is a legacy wild controller route that's not recommended for RESTful applications. | |
- # Note: This route will make all actions in every controller accessible via GET requests. | |
- # match ':controller(/:action(/:id))(.:format)' | |
end | |
diff --git a/db/migrate/.gitkeep b/db/migrate/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/db/migrate/20120924145640_create_diesel_clearance_users.rb b/db/migrate/20120924145640_create_diesel_clearance_users.rb | |
new file mode 100644 | |
index 0000000..4e44358 | |
--- /dev/null | |
+++ b/db/migrate/20120924145640_create_diesel_clearance_users.rb | |
@@ -0,0 +1,19 @@ | |
+class CreateDieselClearanceUsers < ActiveRecord::Migration | |
+ def self.up | |
+ create_table(:users) do |t| | |
+ t.string :email | |
+ t.string :encrypted_password, :limit => 128 | |
+ t.string :salt, :limit => 128 | |
+ t.string :confirmation_token, :limit => 128 | |
+ t.string :remember_token, :limit => 128 | |
+ t.timestamps | |
+ end | |
+ | |
+ add_index :users, :email | |
+ add_index :users, :remember_token | |
+ end | |
+ | |
+ def self.down | |
+ drop_table :users | |
+ end | |
+end | |
diff --git a/features/clearance/visitor_resets_password.feature b/features/clearance/visitor_resets_password.feature | |
new file mode 100644 | |
index 0000000..bd56869 | |
--- /dev/null | |
+++ b/features/clearance/visitor_resets_password.feature | |
@@ -0,0 +1,41 @@ | |
+Feature: Password reset | |
+ | |
+ In order to sign in even if I forgot my password | |
+ As a user | |
+ I want to reset my password | |
+ | |
+ Scenario: User is not signed up | |
+ When I reset the password for "unknown.email@example.com" | |
+ Then I am told email is unknown | |
+ | |
+ Scenario: User is signed up and requests password reset | |
+ Given I signed up with "email@example.com" | |
+ When I reset the password for "email@example.com" | |
+ Then instructions for changing my password are emailed to "email@example.com" | |
+ | |
+ Scenario: User tries to reset his password with a blank password | |
+ Given I signed up with "email@example.com" | |
+ When I reset the password for "email@example.com" | |
+ And I follow the password reset link sent to "email@example.com" | |
+ And I update my password with "" | |
+ Then I am told to enter a password | |
+ And I should be signed out | |
+ | |
+ Scenario: User is signed up and updates his password | |
+ Given I signed up with "email@example.com" | |
+ When I reset the password for "email@example.com" | |
+ And I follow the password reset link sent to "email@example.com" | |
+ And I update my password with "newpassword" | |
+ Then I should be signed in | |
+ When I sign out | |
+ Then I should be signed out | |
+ When I sign in with "email@example.com" and "newpassword" | |
+ Then I should be signed in | |
+ | |
+ Scenario: User who was created before Clearance was installed creates password for first time | |
+ Given a user "email@example.com" exists without a salt, remember token, or password | |
+ When I reset the password for "email@example.com" | |
+ When I follow the password reset link sent to "email@example.com" | |
+ And I update my password with "newpassword" | |
+ Then I should be signed in | |
+ | |
diff --git a/features/clearance/visitor_signs_in.feature b/features/clearance/visitor_signs_in.feature | |
new file mode 100644 | |
index 0000000..86542c8 | |
--- /dev/null | |
+++ b/features/clearance/visitor_signs_in.feature | |
@@ -0,0 +1,26 @@ | |
+Feature: Sign in | |
+ | |
+ In order to get access to protected sections of the site | |
+ As a visitor | |
+ I want to sign in | |
+ | |
+ Scenario: Visitor is not signed up | |
+ When I sign in as "unknown.email@example.com" | |
+ Then I am told email or password is bad | |
+ And I should be signed out | |
+ | |
+ Scenario: Visitor enters wrong password | |
+ Given I am signed up as "email@example.com" | |
+ When I sign in as "email@example.com" and "badpassword" | |
+ Then I am told email or password is bad | |
+ And I should be signed out | |
+ | |
+ Scenario: Visitor signs in successfully | |
+ Given I am signed up as "email@example.com" | |
+ When I sign in as "email@example.com" | |
+ Then I should be signed in | |
+ | |
+ Scenario: Visitor signs in successfully with uppercase email | |
+ Given I am signed up as "email@example.com" | |
+ When I sign in as "Email@example.com" | |
+ Then I should be signed in | |
diff --git a/features/clearance/visitor_signs_out.feature b/features/clearance/visitor_signs_out.feature | |
new file mode 100644 | |
index 0000000..7bb5a36 | |
--- /dev/null | |
+++ b/features/clearance/visitor_signs_out.feature | |
@@ -0,0 +1,12 @@ | |
+Feature: Sign out | |
+ | |
+ In order to protect my account from unauthorized access | |
+ As a signed in user | |
+ I want to sign out | |
+ | |
+ Scenario: User signs out | |
+ Given I am signed up as "email@example.com" | |
+ When I sign in as "email@example.com" | |
+ Then I should be signed in | |
+ When I sign out | |
+ Then I should be signed out | |
diff --git a/features/clearance/visitor_signs_up.feature b/features/clearance/visitor_signs_up.feature | |
new file mode 100644 | |
index 0000000..19787e8 | |
--- /dev/null | |
+++ b/features/clearance/visitor_signs_up.feature | |
@@ -0,0 +1,17 @@ | |
+Feature: Sign up | |
+ | |
+ In order to access protected sections of the site | |
+ As a visitor | |
+ I want to sign up | |
+ | |
+ Scenario: Visitor signs up with invalid email | |
+ When I sign up with "invalidemail" and "password" | |
+ Then I am told to enter a valid email address | |
+ | |
+ Scenario: Visitor signs up with blank password | |
+ When I sign up with "email@example.com" and "" | |
+ Then I am told to enter a password | |
+ | |
+ Scenario: Visitor signs up with valid data | |
+ When I sign up with "email@example.com" and "password" | |
+ Then I should be signed in | |
diff --git a/features/step_definitions/clearance/clearance_steps.rb b/features/step_definitions/clearance/clearance_steps.rb | |
new file mode 100644 | |
index 0000000..6f5d874 | |
--- /dev/null | |
+++ b/features/step_definitions/clearance/clearance_steps.rb | |
@@ -0,0 +1,124 @@ | |
+# Existing users | |
+ | |
+require 'factory_girl_rails' | |
+ | |
+Given /^(?:I am|I have|I) signed up (?:as|with) "(.*)"$/ do |email| | |
+ FactoryGirl.create(:user, :email => email) | |
+end | |
+ | |
+Given /^a user "([^"]*)" exists without a salt, remember token, or password$/ do |email| | |
+ user = FactoryGirl.create(:user, :email => email) | |
+ sql = "update users set salt = NULL, encrypted_password = NULL, remember_token = NULL where id = #{user.id}" | |
+ ActiveRecord::Base.connection.update(sql) | |
+end | |
+ | |
+# Sign up | |
+ | |
+When /^I sign up (?:with|as) "(.*)" and "(.*)"$/ do |email, password| | |
+ visit sign_up_path | |
+ page.should have_css("input[type='email']") | |
+ | |
+ fill_in "Email", :with => email | |
+ fill_in "Password", :with => password | |
+ click_button "Sign up" | |
+end | |
+ | |
+# Sign in | |
+ | |
+Given /^I sign in$/ do | |
+ email = FactoryGirl.generate(:email) | |
+ steps %{ | |
+ I have signed up with "#{email}" | |
+ I sign in with "#{email}" | |
+ } | |
+end | |
+ | |
+When /^I sign in (?:with|as) "([^"]*)"$/ do |email| | |
+ step %{I sign in with "#{email}" and "password"} | |
+end | |
+ | |
+When /^I sign in (?:with|as) "([^"]*)" and "([^"]*)"$/ do |email, password| | |
+ visit sign_in_path | |
+ page.should have_css("input[type='email']") | |
+ | |
+ fill_in "Email", :with => email | |
+ fill_in "Password", :with => password | |
+ click_button "Sign in" | |
+end | |
+ | |
+# Sign out | |
+ | |
+When "I sign out" do | |
+ visit "/" | |
+ click_link "Sign out" | |
+end | |
+ | |
+# Reset password | |
+ | |
+When /^I reset the password for "(.*)"$/ do |email| | |
+ visit new_password_path | |
+ page.should have_css("input[type='email']") | |
+ | |
+ fill_in "Email address", :with => email | |
+ click_button "Reset password" | |
+end | |
+ | |
+Then /^instructions for changing my password are emailed to "(.*)"$/ do |email| | |
+ page.should have_content("instructions for changing your password") | |
+ | |
+ user = User.find_by_email!(email) | |
+ assert !user.confirmation_token.blank? | |
+ assert !ActionMailer::Base.deliveries.empty? | |
+ result = ActionMailer::Base.deliveries.any? do |email| | |
+ email.to == [user.email] && | |
+ email.subject =~ /password/i && | |
+ email.body =~ /#{user.confirmation_token}/ | |
+ end | |
+ assert result | |
+end | |
+ | |
+When /^I follow the password reset link sent to "(.*)"$/ do |email| | |
+ user = User.find_by_email!(email) | |
+ visit edit_user_password_path(:user_id => user, | |
+ :token => user.confirmation_token) | |
+end | |
+ | |
+When /^I change the password of "(.*)" without token$/ do |email| | |
+ user = User.find_by_email!(email) | |
+ visit edit_user_password_path(:user_id => user) | |
+end | |
+ | |
+When /^I update my password with "(.*)"$/ do |password| | |
+ fill_in "Choose password", :with => password | |
+ click_button "Save this password" | |
+end | |
+ | |
+# Flashes | |
+ | |
+Then /^I am told email or password is bad$/ do | |
+ page.should have_content("Bad email or password") | |
+end | |
+ | |
+Then /^I am told email is unknown$/ do | |
+ page.should have_content("Unknown email") | |
+end | |
+ | |
+Then /^I am told to enter a valid email address$/ do | |
+ page.should have_content("Must be a valid email address") | |
+end | |
+ | |
+Then /^I am told to enter a password$/ do | |
+ page.should have_content("Password can't be blank") | |
+end | |
+ | |
+# Verification | |
+ | |
+Then /^I should be signed in$/ do | |
+ visit "/" | |
+ page.should have_content "Sign out" | |
+end | |
+ | |
+Then /^I should be signed out$/ do | |
+ visit "/" | |
+ page.should have_content "Sign in" | |
+end | |
diff --git a/features/support/env.rb b/features/support/env.rb | |
new file mode 100644 | |
index 0000000..3185d35 | |
--- /dev/null | |
+++ b/features/support/env.rb | |
@@ -0,0 +1,17 @@ | |
+require 'spork' | |
+ | |
+Spork.prefork do | |
+ ENV['RAILS_ENV'] ||= 'test' | |
+ require File.expand_path(File.dirname(__FILE__) + '/../../config/environment') | |
+ require 'cucumber/rails' | |
+ | |
+ Capybara.default_selector = :css | |
+ Capybara.javascript_driver = :webkit | |
+ DatabaseCleaner.strategy = :truncation | |
+end | |
+ | |
+Spork.each_run do | |
+ After do | |
+ DatabaseCleaner.clean | |
+ end | |
+end | |
diff --git a/lib/tasks/cucumber.rake b/lib/tasks/cucumber.rake | |
new file mode 100644 | |
index 0000000..83f7947 | |
--- /dev/null | |
+++ b/lib/tasks/cucumber.rake | |
@@ -0,0 +1,65 @@ | |
+# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. | |
+# It is recommended to regenerate this file in the future when you upgrade to a | |
+# newer version of cucumber-rails. Consider adding your own code to a new file | |
+# instead of editing this one. Cucumber will automatically load all features/**/*.rb | |
+# files. | |
+ | |
+ | |
+unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks | |
+ | |
+vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first | |
+$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? | |
+ | |
+begin | |
+ require 'cucumber/rake/task' | |
+ | |
+ namespace :cucumber do | |
+ Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t| | |
+ t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. | |
+ t.fork = true # You may get faster startup if you set this to false | |
+ t.profile = 'default' | |
+ end | |
+ | |
+ Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t| | |
+ t.binary = vendored_cucumber_bin | |
+ t.fork = true # You may get faster startup if you set this to false | |
+ t.profile = 'wip' | |
+ end | |
+ | |
+ Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t| | |
+ t.binary = vendored_cucumber_bin | |
+ t.fork = true # You may get faster startup if you set this to false | |
+ t.profile = 'rerun' | |
+ end | |
+ | |
+ desc 'Run all features' | |
+ task :all => [:ok, :wip] | |
+ | |
+ task :statsetup do | |
+ require 'rails/code_statistics' | |
+ ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features') | |
+ ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features') | |
+ end | |
+ end | |
+ desc 'Alias for cucumber:ok' | |
+ task :cucumber => 'cucumber:ok' | |
+ | |
+ task :default => :cucumber | |
+ | |
+ task :features => :cucumber do | |
+ STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" | |
+ end | |
+ | |
+ # In case we don't have ActiveRecord, append a no-op task that we can depend upon. | |
+ task 'db:test:prepare' do | |
+ end | |
+ | |
+ task :stats => 'cucumber:statsetup' | |
+rescue LoadError | |
+ desc 'cucumber rake task not available (cucumber not installed)' | |
+ task :cucumber do | |
+ abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' | |
+ end | |
+end | |
+ | |
+end | |
diff --git a/public/404.html b/public/404.html | |
index 9a48320..a93f7ac 100644 | |
--- a/public/404.html | |
+++ b/public/404.html | |
@@ -1,24 +1,14 @@ | |
<!DOCTYPE html> | |
<html> | |
<head> | |
+ <meta charset='utf-8' /> | |
+ <meta name='ROBOTS' content='NOODP' /> | |
<title>The page you were looking for doesn't exist (404)</title> | |
- <style type="text/css"> | |
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } | |
- div.dialog { | |
- width: 25em; | |
- padding: 0 4em; | |
- margin: 4em auto 0 auto; | |
- border: 1px solid #ccc; | |
- border-right-color: #999; | |
- border-bottom-color: #999; | |
- } | |
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; } | |
- </style> | |
+ <link href='/assets/application.css' media='all' rel='stylesheet' type='text/css' /> | |
</head> | |
<body> | |
- <!-- This file lives in public/404.html --> | |
- <div class="dialog"> | |
+ <div class="dialog"> | |
<h1>The page you were looking for doesn't exist.</h1> | |
<p>You may have mistyped the address or the page may have moved.</p> | |
</div> | |
diff --git a/public/422.html b/public/422.html | |
index 83660ab..7299e45 100644 | |
--- a/public/422.html | |
+++ b/public/422.html | |
@@ -1,24 +1,14 @@ | |
<!DOCTYPE html> | |
<html> | |
<head> | |
+ <meta charset='utf-8' /> | |
+ <meta name='ROBOTS' content='NOODP' /> | |
<title>The change you wanted was rejected (422)</title> | |
- <style type="text/css"> | |
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } | |
- div.dialog { | |
- width: 25em; | |
- padding: 0 4em; | |
- margin: 4em auto 0 auto; | |
- border: 1px solid #ccc; | |
- border-right-color: #999; | |
- border-bottom-color: #999; | |
- } | |
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; } | |
- </style> | |
+ <link href='/assets/application.css' media='all' rel='stylesheet' type='text/css' /> | |
</head> | |
<body> | |
- <!-- This file lives in public/422.html --> | |
- <div class="dialog"> | |
+ <div class="dialog"> | |
<h1>The change you wanted was rejected.</h1> | |
<p>Maybe you tried to change something you didn't have access to.</p> | |
</div> | |
diff --git a/public/500.html b/public/500.html | |
index f3648a0..090f5f3 100644 | |
--- a/public/500.html | |
+++ b/public/500.html | |
@@ -1,24 +1,14 @@ | |
<!DOCTYPE html> | |
<html> | |
<head> | |
+ <meta charset='utf-8' /> | |
+ <meta name='ROBOTS' content='NOODP' /> | |
<title>We're sorry, but something went wrong (500)</title> | |
- <style type="text/css"> | |
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } | |
- div.dialog { | |
- width: 25em; | |
- padding: 0 4em; | |
- margin: 4em auto 0 auto; | |
- border: 1px solid #ccc; | |
- border-right-color: #999; | |
- border-bottom-color: #999; | |
- } | |
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; } | |
- </style> | |
+ <link href='/assets/application.css' media='all' rel='stylesheet' type='text/css' /> | |
</head> | |
<body> | |
- <!-- This file lives in public/500.html --> | |
- <div class="dialog"> | |
+ <div class="dialog"> | |
<h1>We're sorry, but something went wrong.</h1> | |
</div> | |
</body> | |
diff --git a/public/index.html b/public/index.html | |
deleted file mode 100644 | |
index a1d5099..0000000 | |
--- a/public/index.html | |
+++ /dev/null | |
@@ -1,241 +0,0 @@ | |
-<!DOCTYPE html> | |
-<html> | |
- <head> | |
- <title>Ruby on Rails: Welcome aboard</title> | |
- <style type="text/css" media="screen"> | |
- body { | |
- margin: 0; | |
- margin-bottom: 25px; | |
- padding: 0; | |
- background-color: #f0f0f0; | |
- font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana"; | |
- font-size: 13px; | |
- color: #333; | |
- } | |
- | |
- h1 { | |
- font-size: 28px; | |
- color: #000; | |
- } | |
- | |
- a {color: #03c} | |
- a:hover { | |
- background-color: #03c; | |
- color: white; | |
- text-decoration: none; | |
- } | |
- | |
- | |
- #page { | |
- background-color: #f0f0f0; | |
- width: 750px; | |
- margin: 0; | |
- margin-left: auto; | |
- margin-right: auto; | |
- } | |
- | |
- #content { | |
- float: left; | |
- background-color: white; | |
- border: 3px solid #aaa; | |
- border-top: none; | |
- padding: 25px; | |
- width: 500px; | |
- } | |
- | |
- #sidebar { | |
- float: right; | |
- width: 175px; | |
- } | |
- | |
- #footer { | |
- clear: both; | |
- } | |
- | |
- #header, #about, #getting-started { | |
- padding-left: 75px; | |
- padding-right: 30px; | |
- } | |
- | |
- | |
- #header { | |
- background-image: url("assets/rails.png"); | |
- background-repeat: no-repeat; | |
- background-position: top left; | |
- height: 64px; | |
- } | |
- #header h1, #header h2 {margin: 0} | |
- #header h2 { | |
- color: #888; | |
- font-weight: normal; | |
- font-size: 16px; | |
- } | |
- | |
- | |
- #about h3 { | |
- margin: 0; | |
- margin-bottom: 10px; | |
- font-size: 14px; | |
- } | |
- | |
- #about-content { | |
- background-color: #ffd; | |
- border: 1px solid #fc0; | |
- margin-left: -55px; | |
- margin-right: -10px; | |
- } | |
- #about-content table { | |
- margin-top: 10px; | |
- margin-bottom: 10px; | |
- font-size: 11px; | |
- border-collapse: collapse; | |
- } | |
- #about-content td { | |
- padding: 10px; | |
- padding-top: 3px; | |
- padding-bottom: 3px; | |
- } | |
- #about-content td.name {color: #555} | |
- #about-content td.value {color: #000} | |
- | |
- #about-content ul { | |
- padding: 0; | |
- list-style-type: none; | |
- } | |
- | |
- #about-content.failure { | |
- background-color: #fcc; | |
- border: 1px solid #f00; | |
- } | |
- #about-content.failure p { | |
- margin: 0; | |
- padding: 10px; | |
- } | |
- | |
- | |
- #getting-started { | |
- border-top: 1px solid #ccc; | |
- margin-top: 25px; | |
- padding-top: 15px; | |
- } | |
- #getting-started h1 { | |
- margin: 0; | |
- font-size: 20px; | |
- } | |
- #getting-started h2 { | |
- margin: 0; | |
- font-size: 14px; | |
- font-weight: normal; | |
- color: #333; | |
- margin-bottom: 25px; | |
- } | |
- #getting-started ol { | |
- margin-left: 0; | |
- padding-left: 0; | |
- } | |
- #getting-started li { | |
- font-size: 18px; | |
- color: #888; | |
- margin-bottom: 25px; | |
- } | |
- #getting-started li h2 { | |
- margin: 0; | |
- font-weight: normal; | |
- font-size: 18px; | |
- color: #333; | |
- } | |
- #getting-started li p { | |
- color: #555; | |
- font-size: 13px; | |
- } | |
- | |
- | |
- #sidebar ul { | |
- margin-left: 0; | |
- padding-left: 0; | |
- } | |
- #sidebar ul h3 { | |
- margin-top: 25px; | |
- font-size: 16px; | |
- padding-bottom: 10px; | |
- border-bottom: 1px solid #ccc; | |
- } | |
- #sidebar li { | |
- list-style-type: none; | |
- } | |
- #sidebar ul.links li { | |
- margin-bottom: 5px; | |
- } | |
- | |
- .filename { | |
- font-style: italic; | |
- } | |
- </style> | |
- <script type="text/javascript"> | |
- function about() { | |
- info = document.getElementById('about-content'); | |
- if (window.XMLHttpRequest) | |
- { xhr = new XMLHttpRequest(); } | |
- else | |
- { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } | |
- xhr.open("GET","rails/info/properties",false); | |
- xhr.send(""); | |
- info.innerHTML = xhr.responseText; | |
- info.style.display = 'block' | |
- } | |
- </script> | |
- </head> | |
- <body> | |
- <div id="page"> | |
- <div id="sidebar"> | |
- <ul id="sidebar-items"> | |
- <li> | |
- <h3>Browse the documentation</h3> | |
- <ul class="links"> | |
- <li><a href="http://guides.rubyonrails.org/">Rails Guides</a></li> | |
- <li><a href="http://api.rubyonrails.org/">Rails API</a></li> | |
- <li><a href="http://www.ruby-doc.org/core/">Ruby core</a></li> | |
- <li><a href="http://www.ruby-doc.org/stdlib/">Ruby standard library</a></li> | |
- </ul> | |
- </li> | |
- </ul> | |
- </div> | |
- | |
- <div id="content"> | |
- <div id="header"> | |
- <h1>Welcome aboard</h1> | |
- <h2>You’re riding Ruby on Rails!</h2> | |
- </div> | |
- | |
- <div id="about"> | |
- <h3><a href="rails/info/properties" onclick="about(); return false">About your application’s environment</a></h3> | |
- <div id="about-content" style="display: none"></div> | |
- </div> | |
- | |
- <div id="getting-started"> | |
- <h1>Getting started</h1> | |
- <h2>Here’s how to get rolling:</h2> | |
- | |
- <ol> | |
- <li> | |
- <h2>Use <code>rails generate</code> to create your models and controllers</h2> | |
- <p>To see all available options, run it without parameters.</p> | |
- </li> | |
- | |
- <li> | |
- <h2>Set up a default route and remove <span class="filename">public/index.html</span></h2> | |
- <p>Routes are set up in <span class="filename">config/routes.rb</span>.</p> | |
- </li> | |
- | |
- <li> | |
- <h2>Create your database</h2> | |
- <p>Run <code>rake db:create</code> to create your database. If you're not using SQLite (the default), edit <span class="filename">config/database.yml</span> with your username and password.</p> | |
- </li> | |
- </ol> | |
- </div> | |
- </div> | |
- | |
- <div id="footer"> </div> | |
- </div> | |
- </body> | |
-</html> | |
diff --git a/script/cucumber b/script/cucumber | |
new file mode 100755 | |
index 0000000..7fa5c92 | |
--- /dev/null | |
+++ b/script/cucumber | |
@@ -0,0 +1,10 @@ | |
+#!/usr/bin/env ruby | |
+ | |
+vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first | |
+if vendored_cucumber_bin | |
+ load File.expand_path(vendored_cucumber_bin) | |
+else | |
+ require 'rubygems' unless ENV['NO_RUBYGEMS'] | |
+ require 'cucumber' | |
+ load Cucumber::BINARY | |
+end | |
diff --git a/spec/controllers/.gitkeep b/spec/controllers/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/spec/factories/clearance.rb b/spec/factories/clearance.rb | |
new file mode 100644 | |
index 0000000..36144a3 | |
--- /dev/null | |
+++ b/spec/factories/clearance.rb | |
@@ -0,0 +1,12 @@ | |
+FactoryGirl.define do | |
+ | |
+ sequence :email do |n| | |
+ "user#{n}@example.com" | |
+ end | |
+ | |
+ factory :user do | |
+ password "password" | |
+ end | |
+ | |
+end | |
diff --git a/spec/helpers/.gitkeep b/spec/helpers/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/spec/lib/.gitkeep b/spec/lib/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/spec/models/.gitkeep b/spec/models/.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..bfd7ae0 | |
--- /dev/null | |
+++ b/spec/spec_helper.rb | |
@@ -0,0 +1,32 @@ | |
+# This file is copied to spec/ when you run 'rails generate rspec:install' | |
+ENV["RAILS_ENV"] ||= 'test' | |
+require File.expand_path("../../config/environment", __FILE__) | |
+require 'rspec/rails' | |
+require 'rspec/autorun' | |
+ | |
+# Requires supporting ruby files with custom matchers and macros, etc, | |
+# in spec/support/ and its subdirectories. | |
+Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} | |
+ | |
+RSpec.configure do |config| | |
+ # ## Mock Framework | |
+ # | |
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: | |
+ # | |
+ config.mock_with :mocha | |
+ # config.mock_with :flexmock | |
+ # config.mock_with :rr | |
+ | |
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures | |
+ config.fixture_path = "#{::Rails.root}/spec/fixtures" | |
+ | |
+ # 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 = true | |
+ | |
+ # If true, the base class of anonymous controllers will be inferred | |
+ # automatically. This will be the default behavior in future versions of | |
+ # rspec-rails. | |
+ config.infer_base_class_for_anonymous_controllers = false | |
+end | |
diff --git a/spec/support/.gitkeep b/spec/support/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/spec/support/clearance.rb b/spec/support/clearance.rb | |
new file mode 100644 | |
index 0000000..2eda1ea | |
--- /dev/null | |
+++ b/spec/support/clearance.rb | |
@@ -0,0 +1 @@ | |
+require 'clearance/testing' | |
\ No newline at end of file | |
diff --git a/spec/support/factory_girl.rb b/spec/support/factory_girl.rb | |
new file mode 100644 | |
index 0000000..eec437f | |
--- /dev/null | |
+++ b/spec/support/factory_girl.rb | |
@@ -0,0 +1,3 @@ | |
+RSpec.configure do |config| | |
+ config.include FactoryGirl::Syntax::Methods | |
+end | |
diff --git a/spec/support/matchers/.gitkeep b/spec/support/matchers/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/spec/support/mixins/.gitkeep b/spec/support/mixins/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/spec/support/shared_examples/.gitkeep b/spec/support/shared_examples/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/spec/views/.gitkeep b/spec/views/.gitkeep | |
new file mode 100644 | |
index 0000000..e69de29 | |
diff --git a/test/fixtures/.gitkeep b/test/fixtures/.gitkeep | |
deleted file mode 100644 | |
index e69de29..0000000 | |
diff --git a/test/functional/.gitkeep b/test/functional/.gitkeep | |
deleted file mode 100644 | |
index e69de29..0000000 | |
diff --git a/test/integration/.gitkeep b/test/integration/.gitkeep | |
deleted file mode 100644 | |
index e69de29..0000000 | |
diff --git a/test/performance/browsing_test.rb b/test/performance/browsing_test.rb | |
deleted file mode 100644 | |
index 3fea27b..0000000 | |
--- a/test/performance/browsing_test.rb | |
+++ /dev/null | |
@@ -1,12 +0,0 @@ | |
-require 'test_helper' | |
-require 'rails/performance_test_help' | |
- | |
-class BrowsingTest < ActionDispatch::PerformanceTest | |
- # Refer to the documentation for all available options | |
- # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory] | |
- # :output => 'tmp/performance', :formats => [:flat] } | |
- | |
- def test_homepage | |
- get '/' | |
- end | |
-end | |
diff --git a/test/test_helper.rb b/test/test_helper.rb | |
deleted file mode 100644 | |
index 8bf1192..0000000 | |
--- a/test/test_helper.rb | |
+++ /dev/null | |
@@ -1,13 +0,0 @@ | |
-ENV["RAILS_ENV"] = "test" | |
-require File.expand_path('../../config/environment', __FILE__) | |
-require 'rails/test_help' | |
- | |
-class ActiveSupport::TestCase | |
- # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. | |
- # | |
- # Note: You'll currently still have to declare fixtures explicitly in integration tests | |
- # -- they do not yet inherit this setting | |
- fixtures :all | |
- | |
- # Add more helper methods to be used by all tests here... | |
-end | |
diff --git a/test/unit/.gitkeep b/test/unit/.gitkeep | |
deleted file mode 100644 | |
index e69de29..0000000 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment