├── .gitignore ├── .ruby-gemset ├── .ruby-version ├── Gemfile ├── Gemfile.lock ├── README ├── README.textile ├── Rakefile ├── app ├── assets │ ├── javascripts │ │ ├── application.js │ │ └── home.js.coffee │ └── stylesheets │ │ ├── application.css.scss │ │ ├── bootstrap_and_overrides.css.scss │ │ └── home.css.scss ├── controllers │ ├── application_controller.rb │ ├── confirmations_controller.rb │ ├── home_controller.rb │ ├── registrations_controller.rb │ └── users_controller.rb ├── helpers │ ├── application_helper.rb │ └── home_helper.rb ├── mailers │ ├── .gitkeep │ └── user_mailer.rb ├── models │ ├── .gitkeep │ ├── ability.rb │ ├── role.rb │ └── user.rb └── views │ ├── devise │ ├── confirmations │ │ └── show.html.erb │ ├── mailer │ │ └── confirmation_instructions.html.erb │ ├── registrations │ │ ├── _thankyou.html.erb │ │ ├── edit.html.erb │ │ └── new.html.erb │ ├── sessions │ │ └── new.html.erb │ └── shared │ │ └── _links.html.erb │ ├── home │ └── index.html.erb │ ├── layouts │ ├── _messages.html.erb │ ├── _navigation.html.erb │ └── application.html.erb │ ├── user_mailer │ ├── welcome_email.html.erb │ └── welcome_email.text.erb │ └── users │ ├── _user.html.erb │ ├── index.html.erb │ └── show.html.erb ├── config.ru ├── config ├── application.example.yml ├── application.rb ├── application.yml ├── boot.rb ├── cucumber.yml ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── backtrace_silencers.rb │ ├── devise.rb │ ├── generators.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── rolify.rb │ ├── secret_token.rb │ ├── session_store.rb │ ├── simple_form.rb │ ├── simple_form_bootstrap.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ ├── en.yml │ └── simple_form.en.yml └── routes.rb ├── db ├── migrate │ ├── 20120826102841_devise_create_users.rb │ ├── 20120826102844_add_name_to_users.rb │ ├── 20120826102849_add_confirmable_to_users.rb │ └── 20120826102855_rolify_create_roles.rb ├── schema.rb └── seeds.rb ├── features ├── admin │ ├── send_invitations.feature │ └── view_progress.feature ├── step_definitions │ ├── admin_steps.rb │ ├── email_steps.rb │ ├── user_steps.rb │ └── visitor_steps.rb ├── support │ ├── email_spec.rb │ ├── env.rb │ └── paths.rb ├── users │ ├── sign_in.feature │ ├── sign_out.feature │ ├── user_edit.feature │ └── user_show.feature └── visitors │ └── request_invitation.feature ├── lib ├── assets │ └── .gitkeep ├── tasks │ ├── .gitkeep │ └── cucumber.rake └── templates │ └── erb │ └── scaffold │ └── _form.html.erb ├── log └── .gitkeep ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico ├── humans.txt ├── robots.txt └── thankyou.html ├── script ├── cucumber └── rails ├── spec ├── controllers │ ├── home_controller_spec.rb │ └── users_controller_spec.rb ├── factories │ └── users.rb ├── mailers │ └── user_mailer_spec.rb ├── models │ └── user_spec.rb ├── spec_helper.rb └── support │ └── devise.rb └── vendor ├── assets ├── javascripts │ └── .gitkeep └── stylesheets │ └── .gitkeep └── plugins └── .gitkeep /.gitignore: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------------- 2 | # Ignore these files when commiting to a git repository. 3 | # 4 | # See http://help.github.com/ignore-files/ for more about ignoring files. 5 | # 6 | # The original version of this file is found here: 7 | # https://github.com/RailsApps/rails-composer/blob/master/files/gitignore.txt 8 | # 9 | # Corrections? Improvements? Create a GitHub issue: 10 | # http://github.com/RailsApps/rails-composer/issues 11 | #---------------------------------------------------------------------------- 12 | 13 | # bundler state 14 | /.bundle 15 | /vendor/bundle/ 16 | /vendor/ruby/ 17 | 18 | # minimal Rails specific artifacts 19 | db/*.sqlite3 20 | /log/* 21 | /tmp/* 22 | 23 | # various artifacts 24 | **.war 25 | *.rbc 26 | *.sassc 27 | .rspec 28 | .redcar/ 29 | .sass-cache 30 | /config/config.yml 31 | /config/database.yml 32 | /coverage.data 33 | /coverage/ 34 | /db/*.javadb/ 35 | /db/*.sqlite3 36 | /doc/api/ 37 | /doc/app/ 38 | /doc/features.html 39 | /doc/specs.html 40 | /public/cache 41 | /public/stylesheets/compiled 42 | /public/system/* 43 | /spec/tmp/* 44 | /cache 45 | /capybara* 46 | /capybara-*.html 47 | /gems 48 | /specifications 49 | rerun.txt 50 | pickle-email-*.html 51 | 52 | # If you find yourself ignoring temporary files generated by your text editor 53 | # or operating system, you probably want to add a global ignore instead: 54 | # git config --global core.excludesfile ~/.gitignore_global 55 | # 56 | # Here are some files you may want to ignore globally: 57 | 58 | # scm revert files 59 | **.orig 60 | 61 | # Mac finder artifacts 62 | .DS_Store 63 | 64 | # Netbeans project directory 65 | /nbproject/ 66 | 67 | # RubyMine project files 68 | .idea 69 | 70 | # Textmate project files 71 | /*.tmproj 72 | 73 | # vim artifacts 74 | **.swp 75 | 76 | # Ignore application configuration 77 | /config/application.yml 78 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | rails-prelaunch-signup 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.0.0 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'rails', '3.2.13' 3 | gem 'sqlite3' 4 | group :assets do 5 | gem 'sass-rails', '~> 3.2.3' 6 | gem 'coffee-rails', '~> 3.2.1' 7 | gem 'uglifier', '>= 1.0.3' 8 | end 9 | gem 'jquery-rails' 10 | gem "rspec-rails", ">= 2.12.2", :group => [:development, :test] 11 | gem "database_cleaner", ">= 1.0.0.RC1", :group => :test 12 | gem "email_spec", ">= 1.4.0", :group => :test 13 | gem "cucumber-rails", ">= 1.3.1", :group => :test, :require => false 14 | gem "launchy", ">= 2.2.0", :group => :test 15 | gem "capybara", ">= 2.0.3", :group => :test 16 | gem "factory_girl_rails", ">= 4.2.0", :group => [:development, :test] 17 | gem "bootstrap-sass", ">= 2.3.0.0" 18 | gem "devise", ">= 2.2.3" 19 | gem "cancan", ">= 1.6.9" 20 | gem "rolify", ">= 3.2.0" 21 | gem "simple_form", ">= 2.1.0" 22 | gem "gibbon", ">= 0.4.2" 23 | gem "selenium-webdriver", "~> 2.32.1" 24 | gem "quiet_assets", ">= 1.0.2", :group => :development 25 | gem "figaro", ">= 0.6.3" 26 | gem "better_errors", ">= 0.7.2", :group => :development 27 | gem "binding_of_caller", ">= 0.7.1", :group => :development, :platforms => [:mri_19, :rbx] -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (3.2.13) 5 | actionpack (= 3.2.13) 6 | mail (~> 2.5.3) 7 | actionpack (3.2.13) 8 | activemodel (= 3.2.13) 9 | activesupport (= 3.2.13) 10 | builder (~> 3.0.0) 11 | erubis (~> 2.7.0) 12 | journey (~> 1.0.4) 13 | rack (~> 1.4.5) 14 | rack-cache (~> 1.2) 15 | rack-test (~> 0.6.1) 16 | sprockets (~> 2.2.1) 17 | activemodel (3.2.13) 18 | activesupport (= 3.2.13) 19 | builder (~> 3.0.0) 20 | activerecord (3.2.13) 21 | activemodel (= 3.2.13) 22 | activesupport (= 3.2.13) 23 | arel (~> 3.0.2) 24 | tzinfo (~> 0.3.29) 25 | activeresource (3.2.13) 26 | activemodel (= 3.2.13) 27 | activesupport (= 3.2.13) 28 | activesupport (3.2.13) 29 | i18n (= 0.6.1) 30 | multi_json (~> 1.0) 31 | addressable (2.3.4) 32 | arel (3.0.2) 33 | bcrypt-ruby (3.0.1) 34 | better_errors (0.8.0) 35 | coderay (>= 1.0.0) 36 | erubis (>= 2.6.6) 37 | binding_of_caller (0.7.1) 38 | debug_inspector (>= 0.0.1) 39 | bootstrap-sass (2.3.1.0) 40 | sass (~> 3.2) 41 | builder (3.0.4) 42 | cancan (1.6.10) 43 | capybara (2.1.0) 44 | mime-types (>= 1.16) 45 | nokogiri (>= 1.3.3) 46 | rack (>= 1.0.0) 47 | rack-test (>= 0.5.4) 48 | xpath (~> 2.0) 49 | childprocess (0.3.9) 50 | ffi (~> 1.0, >= 1.0.11) 51 | coderay (1.0.9) 52 | coffee-rails (3.2.2) 53 | coffee-script (>= 2.2.0) 54 | railties (~> 3.2.0) 55 | coffee-script (2.2.0) 56 | coffee-script-source 57 | execjs 58 | coffee-script-source (1.6.2) 59 | cucumber (1.3.2) 60 | builder (>= 2.1.2) 61 | diff-lcs (>= 1.1.3) 62 | gherkin (~> 2.12.0) 63 | multi_json (~> 1.3) 64 | cucumber-rails (1.3.1) 65 | capybara (>= 1.1.2) 66 | cucumber (>= 1.2.0) 67 | nokogiri (>= 1.5.0) 68 | rails (~> 3.0) 69 | database_cleaner (1.0.1) 70 | debug_inspector (0.0.2) 71 | devise (2.2.4) 72 | bcrypt-ruby (~> 3.0) 73 | orm_adapter (~> 0.1) 74 | railties (~> 3.1) 75 | warden (~> 1.2.1) 76 | diff-lcs (1.2.4) 77 | email_spec (1.4.0) 78 | launchy (~> 2.1) 79 | mail (~> 2.2) 80 | erubis (2.7.0) 81 | execjs (1.4.0) 82 | multi_json (~> 1.0) 83 | factory_girl (4.2.0) 84 | activesupport (>= 3.0.0) 85 | factory_girl_rails (4.2.1) 86 | factory_girl (~> 4.2.0) 87 | railties (>= 3.0.0) 88 | ffi (1.8.1) 89 | figaro (0.6.4) 90 | bundler (~> 1.0) 91 | rails (>= 3, < 5) 92 | gherkin (2.12.0) 93 | multi_json (~> 1.3) 94 | gibbon (0.4.6) 95 | httparty 96 | multi_json (>= 1.3.4) 97 | hike (1.2.2) 98 | httparty (0.11.0) 99 | multi_json (~> 1.0) 100 | multi_xml (>= 0.5.2) 101 | i18n (0.6.1) 102 | journey (1.0.4) 103 | jquery-rails (2.2.1) 104 | railties (>= 3.0, < 5.0) 105 | thor (>= 0.14, < 2.0) 106 | json (1.8.0) 107 | launchy (2.3.0) 108 | addressable (~> 2.3) 109 | mail (2.5.4) 110 | mime-types (~> 1.16) 111 | treetop (~> 1.4.8) 112 | mime-types (1.23) 113 | multi_json (1.7.3) 114 | multi_xml (0.5.3) 115 | nokogiri (1.5.9) 116 | orm_adapter (0.4.0) 117 | polyglot (0.3.3) 118 | quiet_assets (1.0.2) 119 | railties (>= 3.1, < 5.0) 120 | rack (1.4.5) 121 | rack-cache (1.2) 122 | rack (>= 0.4) 123 | rack-ssl (1.3.3) 124 | rack 125 | rack-test (0.6.2) 126 | rack (>= 1.0) 127 | rails (3.2.13) 128 | actionmailer (= 3.2.13) 129 | actionpack (= 3.2.13) 130 | activerecord (= 3.2.13) 131 | activeresource (= 3.2.13) 132 | activesupport (= 3.2.13) 133 | bundler (~> 1.0) 134 | railties (= 3.2.13) 135 | railties (3.2.13) 136 | actionpack (= 3.2.13) 137 | activesupport (= 3.2.13) 138 | rack-ssl (~> 1.3.2) 139 | rake (>= 0.8.7) 140 | rdoc (~> 3.4) 141 | thor (>= 0.14.6, < 2.0) 142 | rake (10.0.4) 143 | rdoc (3.12.2) 144 | json (~> 1.4) 145 | rolify (3.2.0) 146 | rspec-core (2.13.1) 147 | rspec-expectations (2.13.0) 148 | diff-lcs (>= 1.1.3, < 2.0) 149 | rspec-mocks (2.13.1) 150 | rspec-rails (2.13.2) 151 | actionpack (>= 3.0) 152 | activesupport (>= 3.0) 153 | railties (>= 3.0) 154 | rspec-core (~> 2.13.0) 155 | rspec-expectations (~> 2.13.0) 156 | rspec-mocks (~> 2.13.0) 157 | rubyzip (0.9.9) 158 | sass (3.2.9) 159 | sass-rails (3.2.6) 160 | railties (~> 3.2.0) 161 | sass (>= 3.1.10) 162 | tilt (~> 1.3) 163 | selenium-webdriver (2.32.1) 164 | childprocess (>= 0.2.5) 165 | multi_json (~> 1.0) 166 | rubyzip 167 | websocket (~> 1.0.4) 168 | simple_form (2.1.0) 169 | actionpack (~> 3.0) 170 | activemodel (~> 3.0) 171 | sprockets (2.2.2) 172 | hike (~> 1.2) 173 | multi_json (~> 1.0) 174 | rack (~> 1.0) 175 | tilt (~> 1.1, != 1.3.0) 176 | sqlite3 (1.3.7) 177 | thor (0.18.1) 178 | tilt (1.4.1) 179 | treetop (1.4.12) 180 | polyglot 181 | polyglot (>= 0.3.1) 182 | tzinfo (0.3.37) 183 | uglifier (2.1.1) 184 | execjs (>= 0.3.0) 185 | multi_json (~> 1.0, >= 1.0.2) 186 | warden (1.2.1) 187 | rack (>= 1.0) 188 | websocket (1.0.7) 189 | xpath (2.0.0) 190 | nokogiri (~> 1.3) 191 | 192 | PLATFORMS 193 | ruby 194 | 195 | DEPENDENCIES 196 | better_errors (>= 0.7.2) 197 | binding_of_caller (>= 0.7.1) 198 | bootstrap-sass (>= 2.3.0.0) 199 | cancan (>= 1.6.9) 200 | capybara (>= 2.0.3) 201 | coffee-rails (~> 3.2.1) 202 | cucumber-rails (>= 1.3.1) 203 | database_cleaner (>= 1.0.0.RC1) 204 | devise (>= 2.2.3) 205 | email_spec (>= 1.4.0) 206 | factory_girl_rails (>= 4.2.0) 207 | figaro (>= 0.6.3) 208 | gibbon (>= 0.4.2) 209 | jquery-rails 210 | launchy (>= 2.2.0) 211 | quiet_assets (>= 1.0.2) 212 | rails (= 3.2.13) 213 | rolify (>= 3.2.0) 214 | rspec-rails (>= 2.12.2) 215 | sass-rails (~> 3.2.3) 216 | selenium-webdriver (~> 2.32.1) 217 | simple_form (>= 2.1.0) 218 | sqlite3 219 | uglifier (>= 1.0.3) 220 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Rails Prelaunch Signup 2 | ======================== 3 | 4 | An example Rails 3.2 app for a web startup prelaunch page. 5 | 6 | You can use this project as a starting point for a Rails web application. It requires Rails 3.2 or newer and uses Devise http://github.com/plataformatec/devise for user management and authentication. 7 | ________________________ 8 | 9 | See the README file on GitHub 10 | 11 | For more information, please see the updated README file on GitHub: 12 | 13 | https://github.com/railsapps/rails-prelaunch-signup 14 | 15 | ________________________ 16 | 17 | License 18 | 19 | Contact the author for license terms. -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. !http://railsapps.github.io/images/rails-36x36.jpg(Rails App for a Startup Prelaunch Signup Site)! Rails App for a Startup Prelaunch Signup Site 2 | 3 | Rails 3.2 example application for a “beta launching soon” startup prelaunch signup site. 4 | 5 | * "Rails Prelaunch Signup App":http://railsapps.github.io/rails-prelaunch-signup/ project page 6 | 7 | Best of all, there's a "detailed tutorial":https://tutorials.railsapps.org/rails-prelaunch-signup to show how it is built. 8 | 9 | You can build this application in only a few minutes using the "Rails Composer":http://railsapps.github.io/rails-composer/ tool. 10 | 11 | !http://railsapps.github.io/images/xplaygrounds-screenshot.png(Rails Application for a Startup Prelaunch Signup Site)! 12 | 13 | Read an "interview with Michael Gajda":http://blog.railsapps.org/post/22543541226/powered-up-by-the-railsapps-project-xplaygrounds-com about how he used the project to launch his startup site. 14 | 15 | h4. Notable Forks 16 | 17 | |_. Alternative version |_. |_. Author | 18 | | "rails-prelaunch-signup-1click":https://github.com/chadokruse/rails-prelaunch-signup-1click | single-click email submit (no modal) | "Chad Kruse":http://twitter.com/chadkruser | 19 | 20 | h2. !http://twitter-badges.s3.amazonaws.com/t_logo-a.png(Follow on Twitter)!:http://www.twitter.com/rails_apps Follow on Twitter 21 | 22 | Follow the project on Twitter: "@rails_apps":http://twitter.com/rails_apps. Please tweet some praise if you like what you've found. 23 | 24 | h2. Introduction 25 | 26 | The initial app for a typical web startup announces the founders' plans and encourages visitors to enter an email address for future notification of the site launch. It's not difficult to build such an app in Rails. 27 | 28 | But why build it yourself if others have already done so? This project aims to: 29 | 30 | * eliminate effort spent building an application that meets a common need; 31 | * offer code that is already implemented and tested by a large community; 32 | * provide a well-thought-out app containing most of the features you'll need. 33 | 34 | By using code from this project, you'll be able to: 35 | 36 | * direct your attention to the design and product offer for your prelaunch site; 37 | * get started faster building the ultimate application for your business. 38 | 39 | h2. What Is Implemented — and What Is Not 40 | 41 | This is a complete and fully functional application. 42 | 43 | h4. For the user: 44 | 45 | * an offer with a "request invite" button 46 | * a "request invitation" form in a modal window 47 | * "Thank you" acknowledgement includes social sharing buttons (Twitter, Facebook, Google+) 48 | * visitor receives an email acknowledging their request 49 | * visitor's request for an invitation creates an "unconfirmed" account 50 | * a welcome email when a user is invited by a site administrator 51 | * a link in the welcome email confirms the user's account and sets a password 52 | 53 | h4. For the site owner: 54 | 55 | * administrative dashboard page 56 | * list of all visitors who have requested invitations 57 | * site owner can send individual invitations 58 | * "bulk invitation" feature to send 50, 100, or more invitations 59 | * see status for any user: "uninvited", "confirmed", "last visit" 60 | 61 | h4. Implementation details: 62 | 63 | * Twitter Bootstrap 64 | * modal window for invitation requests updated by AJAX 65 | * Javascript updates the modal window for any form submission errors 66 | * uses an email service provider for transactional email 67 | * captures visitor email addresses for a MailChimp mailing list 68 | 69 | h4. Tutorial shows how to: 70 | 71 | * write user stories 72 | * use Devise for user management and authentication 73 | * use CanCan for role-based authorization 74 | * keep account passwords secret using environment variables 75 | * use git and GitHub for source control 76 | * deploy using Heroku 77 | 78 | h4. Unimplemented 79 | 80 | * queuing (asynchronous processing) for transactional email and MailChimp list capture 81 | * caching 82 | * A/B testing of offers 83 | * Google analytics 84 | * "about" and "contact" pages 85 | 86 | If you add features or improve the implementation, please consider contributing by submitting an issue or pull request from your fork. 87 | 88 | h2. Alternatives 89 | 90 | This is an application for Rails developers who wish to deploy their own application. It is a good stepping stone to building a more complex application for your startup. You'll own your own code and can customize to your needs. 91 | 92 | Unlike a service such as "LaunchRock":http://launchrock.co/, "KickoffLabs":http://kickofflabs.com/ and "Unbounce":http://unbounce.com/, you'll have your own application you can customize as you wish. Just as important, when your visitors sign up, they are creating real user accounts in a user management system you can use after you launch. 93 | 94 | If you do not want to build an application, or you are not a Rails developer, you may wish to consider alternatives. 95 | 96 | h3. Hosted Services 97 | 98 | * "LaunchRock":http://launchrock.com/ - "set up a social launching-soon page in minutes" 99 | * "KickoffLabs":http://www.kickofflabs.com/ - "viral landing pages you'll love in 60 seconds" 100 | * "Prefinery":http://www.prefinery.com/ - "complete beta management platform that encourages social sharing" 101 | * "Unbounce":http://unbounce.com/ - "create, publish & A/B test landing pages" 102 | 103 | h3. WordPress Themes 104 | 105 | WordPress themes are a popular way to stage a startup prelaunch page. 106 | 107 | * "Launch Effect":http://launcheffectapp.com/ - "a WordPress theme for viral launches" 108 | 109 | h3. Similar Projects 110 | 111 | You can find other projects on GitHub that offer similar functionality. 112 | 113 | |_. Author |_. Project |_. Description | 114 | | codelitt | "launchpage-rails":https://github.com/codelitt/launchpage-rails | Signup for two different types of users | 115 | | johngrimes | "t-minus":https://github.com/johngrimes/t-minus | Instant prelaunch page for your Rails 3 app | 116 | | renderedtext | "coming-soon":https://github.com/renderedtext/coming-soon | Sinatra app to show a pre-launch page and collect emails | 117 | | hashrocket | "coming-soon":https://github.com/hashrocket/coming-soon | Sinatra app to register email addresses | 118 | | jbeyers | "django-prelaunch":https://github.com/jbeyers/django-prelaunch | Django app to gather email addresses with a referral mechanism | 119 | 120 | Found others? Please create an issue with your suggestion or email the author. 121 | 122 | h3. Articles and Discussion 123 | 124 | Here are some articles that describe the purpose and options for a startup prelaunch page: 125 | 126 | * "Building An Effective 'Coming Soon' Page for Your Product":http://www.smashingmagazine.com/2011/05/24/building-an-effective-coming-soon-page-for-your-product/ from Smashing Magazine 127 | * "Elements Of A Viral Launch Page":http://spking.com/2011/08/30/roll-your-own-pre-launch-page/ from Smashing Magazine 128 | * "Which Are the Best Startup Prelaunch Pages?":http://www.quora.com/Which-are-the-best-startup-prelaunch-pages from Quora 129 | 130 | Have other suggestions? Please create an issue with your suggestion or email the author. 131 | 132 | h2. RailsApps Examples and Tutorials 133 | 134 | This is one in a series of Rails example apps and tutorials from the "RailsApps Project":http://railsapps.github.io/. 135 | 136 | This application is based on two of the RailsApps example apps: 137 | 138 | * "rails3-devise-rspec-cucumber":https://github.com/RailsApps/rails3-devise-rspec-cucumber 139 | * "rails3-bootstrap-devise-cancan":https://github.com/RailsApps/rails3-bootstrap-devise-cancan 140 | 141 | The first example shows how to set up Devise for user authentication. It also shows how to set up the app to use RSpec and Cucumber for testing. 142 | 143 | The second example shows how to set up Devise and add CanCan to manage access to administrative pages. It also shows how to set up Twitter Bootstrap as a front-end framework for CSS styling. 144 | 145 | You can use this example without studying these example applications; if you find you are lost, it may be helpful to look at the two simpler examples. 146 | 147 | If you want to use the MongoDB datastore instead of ActiveRecord and a SQL database, look at "rails3-mongoid-devise":https://github.com/RailsApps/rails3-mongoid-devise example. 148 | 149 | h2. Tutorial 150 | 151 | An in-depth tutorial is available (subscription required). Subscriptions provide financial support for the RailsApps project. 152 | 153 | You can use the starter app without getting the tutorial. The tutorial provides a detailed explanation of the code: 154 | 155 | h4. "Get the Tutorial":https://tutorials.railsapps.org/rails-prelaunch-signup 156 | 157 | The tutorial documents each step to follow to create the application. Every step is documented concisely, so a complete beginner can create this application without any additional knowledge. However, no explanation is offered for any of the steps, so if you are a beginner, you’re advised to look for an introduction to Rails elsewhere. If you’re new to Rails, see recommendations for a "Rails tutorial":https://tutorials.railsapps.org/rails-tutorial and a list of top resources for "Ruby and Rails":http://railsapps.github.io/ruby-and-rails.html. The article "What is Ruby? And Rails?":http://railsapps.github.io/what-is-ruby-rails.html is a good place to get a basic introduction to Rails. 158 | 159 | If you simply wish to modify the application for your own project, you can generate the application and set it up as described below, without following the tutorial. 160 | 161 | h2. Dependencies 162 | 163 | Before generating your application, you will need: 164 | 165 | * The Ruby language (version 1.9.3 or 2.0.0) 166 | * The Rails gem (version 3.2.13) 167 | 168 | See "Installing Rails":http://railsapps.github.io/installing-rails.html for detailed instructions and advice. 169 | 170 | h2. Accounts You May Need 171 | 172 | Before you start, you may need to set up accounts for hosting and email. 173 | 174 | h3. Hosting 175 | 176 | For easy deployment, use a "platform as a service" provider such as: 177 | 178 | * "Heroku":http://www.heroku.com/ 179 | * "CloudFoundry":http://www.cloudfoundry.com/ 180 | * "EngineYard":http://www.engineyard.com/ 181 | * "OpenShift":https://openshift.redhat.com/app/ 182 | 183 | Instructions are provided for deployment to Heroku. 184 | 185 | h3. Transactional Email 186 | 187 | For simple testing of email, it's easy to use Gmail to send email messages from the application. For deployment, when the application must send dozens or thousands of acknowledgments or invitations, you will need a hosted SMTP relay service (also known as an ESP or "email service provider"). We provide instructions for "Mandrill by MailChimp":http://mandrill.com/. The Mandrill transactional email service integrates well with the MailChimp email list manager service. Plus, you can send up to 12,000 emails/month from the service for free. 188 | 189 | Sign up for a MailChimp account to get started. After you've created your MailChimp account, see the instructions to "Use Mandrill with MailChimp":http://help.mandrill.com/customer/portal/articles/464750-use-mandrill-with-mailchimp. Then get the "Access Information":http://help.mandrill.com/customer/portal/articles/464828-access-information (your SMTP username and password, which is an API key). 190 | 191 | h3. Mailing List 192 | 193 | In addition to sending transactional email messages, you likely will want to send newsletters or announcements to your entire mailing list. The tutorial shows how to add visitors who request an invitation to a "MailChimp":http://mailchimp.com/ list. MailChimp allows you to send up to 12,000 emails/month to list of 2000 or fewer subscribers for free. After you sign up for a MailChimp account, get your API key. Look under "Account" for "API Keys and Authorized Apps." Note that the Mandrill API key (which you get on the "mandrill.com":http://mandrill.com/ site) is different from the MailChimp API key (which you get on the "mailchimp.com":http://mailchimp.com/ site). 194 | 195 | h2. Getting the Application 196 | 197 | You have several options for getting the code. You can _fork_, _clone_, or _generate_. 198 | 199 | h3. Fork 200 | 201 | If you'd like to add features (or bug fixes) to improve the example application, you can fork the GitHub repo and "make pull requests":http://help.github.com/send-pull-requests/. Your code contributions are welcome! 202 | 203 | h3. Clone 204 | 205 | If you want to copy and customize the app with changes that are only useful for your own project, you can clone the GitHub repo. You'll need to search-and-replace the project name throughout the application. You probably should generate the app instead (see below). To clone: 206 | 207 |
208 | $ git clone git://github.com/RailsApps/rails-prelaunch-signup.git 209 |210 | 211 | You'll need "git":http://git-scm.com/ on your machine. See "Rails and Git":http://railsapps.github.io/rails-git.html. 212 | 213 | h3. Generate 214 | 215 | If you want to use the project as a starter app, use the "Rails Composer":http://railsapps.github.io/rails-composer/ tool to generate a new version of the example app. You'll be able to give it your own project name when you generate the app. Generating the application gives you many additional options. 216 | 217 | To build the example application, run the command: 218 | 219 |
220 | $ rails new rails-prelaunch-signup -m https://raw.github.com/RailsApps/rails-composer/master/composer-Rails3_2.rb -T 221 |222 | 223 | Use the @-T@ flag to skip Test::Unit files. 224 | 225 | The @$@ character indicates a shell prompt; don't include it when you run the command. 226 | 227 | This creates a new Rails app named @rails-prelaunch-signup@ on your computer. You can use a different name if you wish. 228 | 229 | You'll see a prompt: 230 | 231 |
232 | question Install an example application? 233 | 1) I want to build my own application 234 | 2) membership/subscription/saas 235 | 3) rails-prelaunch-signup 236 | 4) rails3-bootstrap-devise-cancan 237 | 5) rails3-devise-rspec-cucumber 238 | 6) rails3-mongoid-devise 239 | 7) rails3-mongoid-omniauth 240 | 8) rails3-subdomains 241 |242 | 243 | Choose *rails-prelaunch-signup*. The Rails Composer tool may give you other options (other choices may have been added since these notes were written). 244 | 245 | The application generator template will ask you for additional preferences: 246 | 247 |
248 | question Git branch for the prelaunch app? 249 | 1) wip (work-in-progress) 250 | 2) master 251 | 3) prelaunch 252 | 4) staging 253 | question Git branch for the main app? 254 | 1) None 255 | 2) wip (work-in-progress) 256 | 3) edge 257 | question Web server for development? 258 | 1) WEBrick (default) 259 | 2) Thin 260 | 3) Unicorn 261 | 4) Puma 262 | question Web server for production? 263 | 1) Same as development 264 | 2) Thin 265 | 3) Unicorn 266 | 4) Puma 267 | question Template engine? 268 | 1) ERB 269 | 2) Haml 270 | 3) Slim 271 | extras Set a robots.txt file to ban spiders? (y/n) 272 | extras Use or create a project-specific rvm gemset? (y/n) 273 | extras Create a GitHub repository? (y/n) 274 |275 | 276 | h4. Git Branches 277 | 278 | The application template will create Git branches for you. This allows you to maintain two versions of the application: one for immdediate deployment as a prelaunch app; and another version that you can use for ongoing development. I recommend deploying the prelaunch app in the "master" branch. Work on your ultimate application in a "wip" branch. 279 | 280 | h4. Web Servers 281 | 282 | We recommend Thin in development for speed and less noise in the log files. 283 | 284 | If you plan to deploy to Heroku, select Thin as your production webserver. 285 | 286 | h4. Template Engine 287 | 288 | The example application uses the default "ERB" Rails template engine. Optionally, you can use another template engine, such as Haml or Slim. See instructions for "Haml and Rails":http://railsapps.github.io/rails-haml.html. 289 | 290 | h4. Other Choices 291 | 292 | Set a robots.txt file to ban spiders if you want to keep your new site out of Google search results. 293 | 294 | It is a good idea to use "rvm":https://rvm.io/, the Ruby Version Manager, and create a project-specific rvm gemset (not available on Windows). See "Installing Rails":http://railsapps.github.io/installing-rails.html. 295 | 296 | If you choose to create a GitHub repository, the generator will prompt you for a GitHub username and password. 297 | 298 | h4. Troubleshooting 299 | 300 | If you get an error "OpenSSL certificate verify failed" or "Gem::RemoteFetcher::FetchError: SSL_connect" see the article "OpenSSL errors and Rails":http://railsapps.github.io/openssl-certificate-verify-failed.html. 301 | 302 | If you get an error like this: 303 | 304 |
305 | Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed. 306 | composer Running 'after bundler' callbacks. 307 | The template [...] could not be loaded. 308 | Error: You have already activated ..., but your Gemfile requires .... 309 | Using bundle exec may solve this. 310 |311 | 312 | It's due to conflicting gem versions. See the article "Rails Error: “You have already activated (…)”":http://railsapps.github.io/rails-error-you-have-already-activated.html. 313 | 314 | h3. Edit the README 315 | 316 | If you're storing the app in a GitHub repository, please edit the README files to add a description of the app and your contact info. If you don't change the README, people will think I am the author of your version of the application. 317 | 318 | h2. Getting Started 319 | 320 | See the article "Installing Rails":http://railsapps.github.io/installing-rails.html to make sure your development environment is prepared properly. 321 | 322 | h3. Use RVM 323 | 324 | I recommend using "rvm":https://rvm.io/, the Ruby Version Manager, to create a project-specific gemset for the application. If you generate the application with the Rails Composer tool, you can create a project-specific gemset. 325 | 326 | h3. Install the Required Gems 327 | 328 | Check the Gemfile to see which gems are used by this application. 329 | 330 | If you used the "Rails Composer":http://railsapps.github.io/rails-composer/ tool to generate the example app, the application template script has already run the @bundle install@ command. 331 | 332 | If not, you should run the @bundle install@ command to install the required gems on your computer: 333 | 334 |
335 | $ bundle install 336 |337 | 338 | You can check which gems are installed on your computer with: 339 | 340 |
341 | $ gem list 342 |343 | 344 | Keep in mind that you have installed these gems locally. When you deploy the app to another server, the same gems (and versions) must be available. 345 | 346 | I recommend using "rvm":https://rvm.io/, the Ruby Version Manager, to create a project-specific gemset for the application. See the article "Installing Rails":http://railsapps.github.io/installing-rails.html. 347 | 348 | h3. Configure Email 349 | 350 | You must configure the application for your email account. See the article "Send Email with Rails":http://railsapps.github.io/rails-send-email.html. 351 | 352 | h3. Configure Devise 353 | 354 | You can modify the configuration file for Devise if you want to use something other than the defaults: 355 | 356 | * *config/initializers/devise.rb* 357 | 358 | h3. Configuration File 359 | 360 | The application uses the "figaro gem":https://github.com/laserlemon/figaro to set environment variables. Credentials for your administrator account and email account are set in the *config/application.yml* file. The *.gitignore* file prevents the *config/application.yml* file from being saved in the git repository so your credentials are kept private. See the article "Rails Environment Variables":http://railsapps.github.io/rails-environment-variables.html for more information. 361 | 362 | Modify the file *config/application.yml*: 363 | 364 |
365 | # Add account credentials and API keys here. 366 | # See http://railsapps.github.io/rails-environment-variables.html 367 | # This file should be listed in .gitignore to keep your settings secret! 368 | # Each entry sets a local environment variable and overrides ENV variables in the Unix shell. 369 | # For example, setting: 370 | # GMAIL_USERNAME: Your_Gmail_Username 371 | # makes 'Your_Gmail_Username' available as ENV["GMAIL_USERNAME"] 372 | # Add application configuration variables here, as shown below. 373 | # 374 | MANDRILL_USERNAME: Your_Username 375 | MANDRILL_API_KEY: Your_Mandrill_API_Key 376 | MAILCHIMP_API_KEY: Your_MailChimp_API_Key 377 | MAILCHIMP_LIST_ID: My_List_ID 378 | ADMIN_NAME: First User 379 | ADMIN_EMAIL: user@example.com 380 | ADMIN_PASSWORD: changeme 381 | ROLES: [admin, user] 382 | EMAIL_ADDRESS: user@example.com 383 | DOMAIN: example.com 384 |385 | 386 | We use Mandrill to increase deliverability for email messages from the application. Provide a @MANDRILL_USERNAME@ and @MANDRILL_API_KEY@. 387 | 388 | When visitors sign up to be notified of our launch, we'll add them to a MailChimp list. Add an environment variable for the MailChimp API key: @MAILCHIMP_API_KEY@. You can find the MailChimp API key under the tab for "Account" on the MailChimp website after you log in. Look for the "Api Keys and Authorized Apps" menu item. 389 | 390 | We'll add @MAILCHIMP_LIST_ID@ for the ID of the mailing list we'll set up in MailChimp. To find the list ID, on the MailChimp "Lists" page, look for the dropdown "gear" menu for the mailing list you've created and click "List Settings and Unique ID." At the bottom of the List Settings page, you'll find the unique ID for the mailing list. 391 | 392 | If you wish, set your name, email address, and password for an administrator's account. If you prefer, you can use the default to sign in to the application and edit the account after deployment. It is always a good idea to change the administrator's password after the application is deployed. 393 | 394 | Specify roles in the configuration file. You will need an "admin" role and "user" role. Remove the "VIP" role as we won't use it. 395 | 396 | We'll add @EMAIL_ADDRESS@ to provide the default sender email address we use when sending email from the application. 397 | 398 | Finally, we'll add @DOMAIN@ which is also used when sending email. 399 | 400 | All configuration values in the *config/application.yml* file are available anywhere in the application as environment variables. For example, @ENV["GMAIL_USERNAME"]@ will return the string "Your_Username". 401 | 402 | If you prefer, you can delete the *config/application.yml* file and set each value as an environment variable in the Unix shell. 403 | 404 | h3. Set Up a Database Seed File 405 | 406 | The *db/seeds.rb* file initializes the database with default values. To keep some data private, and consolidate configuration settings in a single location, we use the *config/application.yml* file to set environment variables and then use the environment variables in the *db/seeds.rb* file. 407 | 408 |
409 | puts 'ROLES' 410 | YAML.load(ENV['ROLES']).each do |role| 411 | Role.find_or_create_by_name({ :name => role }, :without_protection => true) 412 | puts 'role: ' << role 413 | end 414 | puts 'DEFAULT USERS' 415 | user = User.find_or_create_by_email :name => ENV['ADMIN_NAME'].dup, :email => ENV['ADMIN_EMAIL'].dup, :password => ENV['ADMIN_PASSWORD'].dup, :password_confirmation => ENV['ADMIN_PASSWORD'].dup 416 | puts 'user: ' << user.name 417 | user.add_role :admin 418 | user.skip_confirmation! 419 | user.save! 420 |421 | 422 | The *db/seeds.rb* file reads a list of roles from the *config/application.yml* file and adds the roles to the database. In fact, any new role can be added to the roles datatable with a statement such @user.add_role :superhero@. Setting the roles in the *db/seeds.rb* file simply makes sure each role is listed and available. 423 | 424 | You can change the administrator name, email, and password in this file but it is better to make the changes in the *config/application.yml* file to keep the credentials private. If you decide to include your private password in the *db/seeds.rb* file, be sure to add the filename to your *.gitignore* file so that your password doesn't become available in your public GitHub repository. 425 | 426 | Note that it's not necessary to personalize the *db/seeds.rb* file before you deploy your app. You can deploy the app with an example user and then use the application's "Edit Account" feature to change name, email address, and password after you log in. Use this feature to log in as an administrator and change the user name and password to your own. 427 | 428 | Don't overlook the @user.skip_confirmation!@ and @user.save!@ statements. This application uses the Devise Confirmable module to require that a user confirm a new account by clicking on a link in an email message. You won't be sending the administrator an email message with a confirmation link so you must set the account with the @user.skip_confirmation!@ and @user.save!@ statements. 429 | 430 | You may wish to include additional sample users: 431 | 432 |
433 | user2 = User.find_or_create_by_email :name => 'Second User', :email => 'user2@example.com', :password => 'changeme', :password_confirmation => 'changeme' 434 | puts 'user: ' << user2.name 435 | user2.add_role :VIP 436 |437 | 438 | This will add a second user to the database with a "VIP" role. 439 | 440 | h3. Set the Database 441 | 442 | Prepare the database and add the default user to the database by running the commands: 443 | 444 |
445 | $ rake db:migrate 446 | $ rake db:seed 447 |448 | 449 | Use @rake db:reset@ if you want to empty and reseed the database. 450 | 451 | Set the database for running tests: 452 | 453 |
454 | $ rake db:test:prepare 455 |456 | 457 | If you’re not using "rvm":https://rvm.io/, the Ruby Version Manager, you should preface each rake command with @bundle exec@. You don’t need to use @bundle exec@ if you are using rvm version 1.11.0 or newer. 458 | 459 | h3. Change your Application's Secret Token 460 | 461 | If you've used the Rails Composer tool to generate the application, the application's secret token will be unique, just as with any Rails application generated with the @rails new@ command. 462 | 463 | However, if you've cloned the application directly from GitHub, it is crucial that you change the application's secret token before deploying your application in production mode. Otherwise, people could change their session information, and potentially access your site without permission. Your secret token should be at least 30 characters long and completely random. 464 | 465 | Get a unique secret token: 466 | 467 |
468 | rake secret 469 |470 | 471 | Edit your *config/initializers/secret_token.rb* file to add the secret token: 472 | 473 |
474 | RailsPrelaunchSignup::Application.config.secret_token = '...some really long, random string...' 475 |476 | 477 | h2. Test the App 478 | 479 | You can check that your app runs properly by entering the command 480 | 481 | @$ rails server@ 482 | 483 | To see your application in action, open a browser window and navigate to "http://localhost:3000/":http://localhost:3000. 484 | 485 | Sign in as the first user (the administrator) using: 486 | 487 | * email: user@example.com 488 | * password: changeme 489 | 490 | You'll see a navigation link for Admin. Clicking the link will display a page with a list of users at 491 | "http://localhost:3000/users":http://localhost:3000/users. 492 | 493 | If you want to see what the administrative dashboard looks like with many users, you can add a line to the *db/seeds.rb* file to create a hundred bogus users: 494 | 495 |
496 | 100.times {|i| User.create! :name => "User #{i+3}", :email => "user#{i+3}@example.com", :password => 'changeme', :password_confirmation => 'changeme'} 497 |498 | 499 | Then run @$ rake db:reset@ to recreate the database and visit the site again. 500 | 501 | h2. Deploy to Heroku 502 | 503 | Heroku provides low cost, easily configured Rails application hosting. 504 | 505 | For your convenience, here is a "Tutorial for Rails on Heroku":http://railsapps.github.io/rails-heroku-tutorial.html. See the article for details about preparing your application to deploy to Heroku. 506 | 507 | Be sure to set up SSL before you make your application available in production. See the "Heroku documentation on SSL":https://devcenter.heroku.com/articles/ssl or use CloudFlare as described in the tutorial. 508 | 509 | After you've prepared your application as described in the "Tutorial for Rails on Heroku":http://railsapps.github.io/rails-heroku-tutorial.html article, precompile assets, commit to git, and push to Heroku: 510 | 511 |
512 | $ rake assets:precompile 513 | $ git add -A 514 | $ git commit -m "assets compiled for Heroku" 515 | $ git push heroku master 516 |517 | 518 | You'll need to set the configuration values from the *config/application.yml* file as Heroku environment variables. See the article "Rails Environment Variables":http://railsapps.github.io/rails-environment-variables.html for more information. 519 | 520 | With the figaro gem, just run: 521 | 522 |
523 | $ rake figaro:heroku 524 |525 | 526 | Alternatively, you can set Heroku environment variables directly. 527 | 528 | Here's how to set environment variables directly on Heroku with @heroku config:add@. 529 | 530 |
531 | $ heroku config:add MANDRILL_USERNAME='Your_Username' MANDRILL_API_KEY='Your_Mandrill_API_Key' 532 | $ heroku config:add MAILCHIMP_LIST_ID='Your_List_ID' 533 | $ heroku config:add ADMIN_NAME='First User' ADMIN_EMAIL='user@example.com' ADMIN_PASSWORD='changeme' 534 | $ heroku config:add 'ROLES=[admin, user]' 535 | $ heroku config:add EMAIL_ADDRESS='me@example.com' DOMAIN='example.com' 536 |537 | 538 | Complete Heroku deployment with: 539 | 540 |
541 | $ heroku run rake db:migrate 542 | $ heroku run rake db:seed 543 |544 | 545 | h2. Testing 546 | 547 | The example application contains a suite of RSpec unit tests and Cucumber scenarios and step definitions. 548 | 549 | After installing the application, run @rake -T@ to check that rake tasks for RSpec and Cucumber are available. 550 | 551 | Run @rake spec@ to run RSpec tests. 552 | 553 | Run @rake cucumber@ (or more simply, @cucumber@) to run Cucumber scenarios. 554 | 555 | Please send the author a message, create an issue, or submit a pull request if you can contribute improved RSpec or Cucumber files. 556 | 557 | h2. Issues 558 | 559 | Please create a "GitHub issue":http://github.com/RailsApps/rails-prelaunch-signup/issues if you identify any problems or have suggestions for improvements. 560 | 561 | h2. Where to Get Help 562 | 563 | Your best source for help with problems is "Stack Overflow":http://stackoverflow.com/questions/tagged/ruby-on-rails-3. Your issue may have been encountered and addressed by others. 564 | 565 | You can also try "Rails Hotline":http://www.railshotline.com/, a free telephone hotline for Rails help staffed by volunteers. 566 | 567 | h2. Contributing 568 | 569 | If you make improvements to this application, please share with others. 570 | 571 | Send the author a message, create an "issue":http://github.com/RailsApps/rails-prelaunch-signup/issues, or fork the project and submit a pull request. 572 | 573 | If you add functionality to this application, create an alternative implementation, or build an application that is similar, please contact me and I'll add a note to the README so that others can find your work. 574 | 575 | h2. Credits 576 | 577 | Daniel Kehoe implemented the application and wrote the tutorial. 578 | 579 | Is the app useful to you? Follow the project on Twitter: "@rails_apps":http://twitter.com/rails_apps 580 | and tweet some praise. I'd love to know you were helped out by what I've put together. 581 | 582 | h2. MIT License 583 | 584 | "MIT License":http://www.opensource.org/licenses/mit-license 585 | 586 | Copyright © 2012 Daniel Kehoe 587 | 588 | h2. Useful Links 589 | 590 | |_. Getting Started |_. Articles |_. Tutorials | 591 | | "Ruby on Rails":http://railsapps.github.io/ruby-and-rails.html | "Analytics for Rails":http://railsapps.github.io/rails-google-analytics.html | "Rails Bootstrap":http://railsapps.github.io/twitter-bootstrap-rails.html | 592 | | "What is Ruby on Rails?":http://railsapps.github.io/what-is-ruby-rails.html | "Heroku and Rails":http://railsapps.github.io/rails-heroku-tutorial.html | "Rails Foundation":http://railsapps.github.io/rails-foundation.html | 593 | | "Learn Ruby on Rails":http://learn-rails.com/learn-ruby-on-rails.html | "JavaScript and Rails":http://railsapps.github.io/rails-javascript-include-external.html | "RSpec Tutorial":http://railsapps.github.io/rspec.html | 594 | | "Rails Tutorial":https://tutorials.railsapps.org/rails-tutorial | "Rails Environment Variables":http://railsapps.github.io/rails-environment-variables.html | "Rails Devise Tutorial":http://railsapps.github.io/tutorial-rails-devise.html | 595 | | "Ruby on Rails Tutorial for Beginners":http://learn-rails.com/ruby-on-rails-tutorial-for-beginners | "Git and GitHub with Rails":http://railsapps.github.io/rails-git.html | "Devise RSpec":http://railsapps.github.io/tutorial-rails-devise-rspec-cucumber.html | 596 | | "Install Ruby on Rails":http://railsapps.github.io/installing-rails.html | "Send Email with Rails":http://railsapps.github.io/rails-send-email.html | "Devise Bootstrap":http://railsapps.github.io/tutorial-rails-bootstrap-devise-cancan.html | 597 | | "Install Ruby on Rails - Mac OS X":http://railsapps.github.io/installrubyonrails-mac.html | "Haml and Rails":http://railsapps.github.io/rails-haml.html | "Rails Membership Site with Stripe":https://tutorials.railsapps.org/rails-stripe-membership-saas | 598 | | "Install Ruby on Rails - Ubuntu":http://railsapps.github.io/installrubyonrails-ubuntu.html | "Rails Application Layout":http://railsapps.github.io/rails-default-application-layout.html | "Rails Subscription Site with Recurly":https://tutorials.railsapps.org/rails-recurly-subscription-saas | 599 | | "Ruby on Rails - Nitrous.io":http://railsapps.github.io/rubyonrails-nitrous-io.html | "HTML5 Boilerplate for Rails":http://railsapps.github.io/rails-html5-boilerplate.html | "Startup Prelaunch Signup Application":https://tutorials.railsapps.org/rails-prelaunch-signup | 600 | | "Update Rails":http://railsapps.github.io/updating-rails.html | "Example Gemfiles for Rails":http://railsapps.github.io/rails-3-2-example-gemfile.html | 601 | | "Rails Composer":http://railsapps.github.io/rails-composer/ | "Rails Application Templates":http://railsapps.github.io/rails-application-templates.html | 602 | | "Rails Examples":http://railsapps.github.io/ | "Rails Product Planning":http://railsapps.github.io/rails-product-planning.html | 603 | | "Rails Starter Apps":http://railsapps.github.io/rails-examples-tutorials.html | "Rails Project Management":http://railsapps.github.io/rails-project-management.html | 604 | 605 | !https://cruel-carlota.pagodabox.com/6ffdc588dd4075aa7827bd7806ed40f7(githalytics.com alpha)! 606 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | RailsPrelaunchSignup::Application.load_tasks 8 | -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require bootstrap 16 | //= require_tree . 17 | $('document').ready(function() { 18 | 19 | // display validation errors for the "request invitation" form 20 | if ($('.alert-error').length > 0) { 21 | $("#request-invite").modal('toggle'); 22 | } 23 | 24 | // use AJAX to submit the "request invitation" form 25 | $('#invitation_button').on('click', function() { 26 | var email = $('form #user_email').val(); 27 | var dataString = 'user[email]='+ email; 28 | $.ajax({ 29 | type: "POST", 30 | url: "/users", 31 | data: dataString, 32 | success: function(data) { 33 | $('#request-invite').html(data); 34 | loadSocial(); 35 | } 36 | }); 37 | return false; 38 | }); 39 | 40 | }) 41 | 42 | // load social sharing scripts if the page includes a Twitter "share" button 43 | function loadSocial() { 44 | 45 | //Twitter 46 | if (typeof (twttr) != 'undefined') { 47 | twttr.widgets.load(); 48 | } else { 49 | $.getScript('http://platform.twitter.com/widgets.js'); 50 | } 51 | 52 | //Facebook 53 | if (typeof (FB) != 'undefined') { 54 | FB.init({ status: true, cookie: true, xfbml: true }); 55 | } else { 56 | $.getScript("http://connect.facebook.net/en_US/all.js#xfbml=1", function () { 57 | FB.init({ status: true, cookie: true, xfbml: true }); 58 | }); 59 | } 60 | 61 | //Google+ 62 | if (typeof (gapi) != 'undefined') { 63 | $(".g-plusone").each(function () { 64 | gapi.plusone.render($(this).get(0)); 65 | }); 66 | } else { 67 | $.getScript('https://apis.google.com/js/plusone.js'); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/assets/javascripts/home.js.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | 15 | .content { 16 | background-color: #eee; 17 | padding: 20px; 18 | margin: 0 -20px; /* negative indent the amount of the padding to maintain the grid system */ 19 | -webkit-border-radius: 0 0 6px 6px; 20 | -moz-border-radius: 0 0 6px 6px; 21 | border-radius: 0 0 6px 6px; 22 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.15); 23 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.15); 24 | box-shadow: 0 1px 2px rgba(0,0,0,.15); 25 | } 26 | -------------------------------------------------------------------------------- /app/assets/stylesheets/bootstrap_and_overrides.css.scss: -------------------------------------------------------------------------------- 1 | @import "bootstrap"; 2 | body { padding-top: 60px; } 3 | @import "bootstrap-responsive"; 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/home.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the home controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | 4 | rescue_from CanCan::AccessDenied do |exception| 5 | redirect_to root_path, :alert => exception.message 6 | end 7 | 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/confirmations_controller.rb: -------------------------------------------------------------------------------- 1 | class ConfirmationsController < Devise::PasswordsController 2 | # Remove the first skip_before_filter (:require_no_authentication) if you 3 | # don't want to enable logged users to access the confirmation page. 4 | skip_before_filter :require_no_authentication 5 | skip_before_filter :authenticate_user! 6 | 7 | # POST /resource/confirmation 8 | def create 9 | self.resource = resource_class.send_confirmation_instructions(resource_params) 10 | if successfully_sent?(resource) 11 | respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name)) 12 | else 13 | respond_with(resource) 14 | end 15 | end 16 | 17 | # PUT /resource/confirmation 18 | def update 19 | with_unconfirmed_confirmable do 20 | if @confirmable.has_no_password? 21 | @confirmable.attempt_set_password(params[:user]) 22 | if @confirmable.valid? 23 | do_confirm 24 | else 25 | do_show 26 | @confirmable.errors.clear #so that we won't render :new 27 | end 28 | else 29 | self.class.add_error_on(self, :email, :password_allready_set) 30 | end 31 | end 32 | 33 | if !@confirmable.errors.empty? 34 | render 'devise/confirmations/new' 35 | end 36 | end 37 | 38 | # GET /resource/confirmation?confirmation_token=abcdef 39 | def show 40 | with_unconfirmed_confirmable do 41 | if @confirmable.has_no_password? 42 | do_show 43 | else 44 | do_confirm 45 | end 46 | end 47 | if !@confirmable.errors.empty? 48 | render 'devise/confirmations/new' 49 | end 50 | end 51 | 52 | protected 53 | 54 | def with_unconfirmed_confirmable 55 | @confirmable = User.find_or_initialize_with_error_by(:confirmation_token, params[:confirmation_token]) 56 | self.resource = @confirmable 57 | if !@confirmable.new_record? 58 | @confirmable.only_if_unconfirmed {yield} 59 | end 60 | end 61 | 62 | def do_show 63 | @confirmation_token = params[:confirmation_token] 64 | @requires_password = true 65 | render 'devise/confirmations/show' 66 | end 67 | 68 | def do_confirm 69 | @confirmable.confirm! 70 | set_flash_message :notice, :confirmed 71 | sign_in_and_redirect(resource_name, @confirmable) 72 | end 73 | 74 | # The path used after resending confirmation instructions. 75 | def after_resending_confirmation_instructions_path_for(resource_name) 76 | new_session_path(resource_name) 77 | end 78 | 79 | # The path used after confirmation. 80 | def after_confirmation_path_for(resource_name, resource) 81 | after_sign_in_path_for(resource) 82 | end 83 | 84 | end 85 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/registrations_controller.rb: -------------------------------------------------------------------------------- 1 | class RegistrationsController < Devise::RegistrationsController 2 | 3 | # override #create to respond to AJAX with a partial 4 | def create 5 | build_resource 6 | 7 | if resource.save 8 | if resource.active_for_authentication? 9 | sign_in(resource_name, resource) 10 | (render(:partial => 'thankyou', :layout => false) && return) if request.xhr? 11 | respond_with resource, :location => after_sign_up_path_for(resource) 12 | else 13 | expire_session_data_after_sign_in! 14 | (render(:partial => 'thankyou', :layout => false) && return) if request.xhr? 15 | respond_with resource, :location => after_inactive_sign_up_path_for(resource) 16 | end 17 | else 18 | clean_up_passwords resource 19 | render :action => :new, :layout => !request.xhr? 20 | end 21 | end 22 | 23 | protected 24 | 25 | def after_inactive_sign_up_path_for(resource) 26 | # the page prelaunch visitors will see after they request an invitation 27 | # unless Ajax is used to return a partial 28 | '/thankyou.html' 29 | end 30 | 31 | def after_sign_up_path_for(resource) 32 | # the page new users will see after sign up (after launch, when no invitation is needed) 33 | redirect_to root_path 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_filter :authenticate_user! 3 | 4 | def index 5 | authorize! :index, @user, :message => 'Not authorized as an administrator.' 6 | @users = User.all 7 | end 8 | 9 | def show 10 | @user = User.find(params[:id]) 11 | end 12 | 13 | def update 14 | authorize! :update, @user, :message => 'Not authorized as an administrator.' 15 | @user = User.find(params[:id]) 16 | if @user.update_attributes(params[:user], :as => :admin) 17 | redirect_to users_path, :notice => "User updated." 18 | else 19 | redirect_to users_path, :alert => "Unable to update user." 20 | end 21 | end 22 | 23 | def destroy 24 | authorize! :destroy, @user, :message => 'Not authorized as an administrator.' 25 | user = User.find(params[:id]) 26 | unless user == current_user 27 | user.destroy 28 | redirect_to users_path, :notice => "User deleted." 29 | else 30 | redirect_to users_path, :notice => "Can't delete yourself." 31 | end 32 | end 33 | 34 | def invite 35 | authorize! :invite, @user, :message => 'Not authorized as an administrator.' 36 | @user = User.find(params[:id]) 37 | @user.send_confirmation_instructions 38 | redirect_to :back, :only_path => true, :notice => "Sent invitation to #{@user.email}." 39 | end 40 | 41 | def bulk_invite 42 | authorize! :bulk_invite, @user, :message => 'Not authorized as an administrator.' 43 | users = User.where(:confirmation_token => nil).order(:created_at).limit(params[:quantity]) 44 | count = users.count 45 | users.each do |user| 46 | user.send_confirmation_instructions 47 | end 48 | redirect_to :back, :only_path => true, :notice => "Sent invitation to #{count} users." 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | def display_base_errors resource 4 | return '' if (resource.errors.empty?) or (resource.errors[:base].empty?) 5 | messages = resource.errors[:base].map { |msg| content_tag(:p, msg) }.join 6 | html = <<-HTML 7 |
Welcome <%= @resource.email %>!
2 | 3 |We're pleased to invite you to try <%= link_to ENV["DOMAIN"], root_url %>.
4 | 5 |Please click the link below to confirm your email address and set your password:
6 | 7 |<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>
8 | -------------------------------------------------------------------------------- /app/views/devise/registrations/_thankyou.html.erb: -------------------------------------------------------------------------------- 1 |Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete %>.
14 | <%= link_to "Back", :back %> 15 | -------------------------------------------------------------------------------- /app/views/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 |9 | We have received your request for an invitation to <%= link_to ENV["DOMAIN"], root_url %>. 10 |
11 |12 | We'll contact you when we launch. 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /app/views/user_mailer/welcome_email.text.erb: -------------------------------------------------------------------------------- 1 | Welcome! 2 | 3 | We have received your request for an invitation to <%= link_to ENV["DOMAIN"], root_url %>. 4 | 5 | We'll contact you when we launch. 6 | -------------------------------------------------------------------------------- /app/views/users/_user.html.erb: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 |4 | Send Bulk Invitations: 5 | <%= link_to "10 ·".html_safe, bulk_invite_path(:quantity => '10') %> 6 | <%= link_to "50 ·".html_safe, bulk_invite_path(:quantity => '50') %> 7 | <%= link_to "100 ·".html_safe, bulk_invite_path(:quantity => '100') %> 8 | <%= link_to "500 ·".html_safe, bulk_invite_path(:quantity => '500') %> 9 | <%= link_to "1000", bulk_invite_path(:quantity => '1000') %> 10 |
11 |Username | 15 |Requested | 17 |Invitation | 18 |Joined | 19 |Visits | 20 |Most Recent | 21 |Role | 22 |23 | | 24 | | |
---|---|---|---|---|---|---|---|---|---|
<%= link_to user.name, user %> | 30 |<%= user.email %> | 31 |<%= user.created_at.to_date %> | 32 |<%= (user.confirmation_token.nil? ? (link_to "send invitation", invite_user_path(user), {:class => 'btn btn-mini'}) : (link_to "resend", invite_user_path(user), {:class => 'btn btn-mini'})) unless user.confirmed_at %> | 33 |<%= user.confirmed_at.to_date if user.confirmed_at %> | 34 |<%= user.sign_in_count if user.sign_in_count %> | 35 |<%= user.last_sign_in_at.to_date if user.last_sign_in_at %> | 36 |<%= user.roles.first.name.titleize unless user.roles.first.nil? %> | 37 |38 | Change role 39 | <%= render user %> 40 | | 41 |<%= link_to("Delete user", user_path(user), :data => { :confirm => "Are you sure?" }, :method => :delete, :class => 'btn btn-mini') unless user == current_user %> | 42 |
User: <%= @user.name %>
3 |Email: <%= @user.email if @user.email %>
4 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run RailsPrelaunchSignup::Application 5 | -------------------------------------------------------------------------------- /config/application.example.yml: -------------------------------------------------------------------------------- 1 | # Add account credentials and API keys here. 2 | # See http://railsapps.github.io/rails-environment-variables.html 3 | # This file should be listed in .gitignore to keep your settings secret! 4 | # Each entry sets a local environment variable and overrides ENV variables in the Unix shell. 5 | # For example, setting: 6 | # GMAIL_USERNAME: Your_Gmail_Username 7 | # makes 'Your_Gmail_Username' available as ENV["GMAIL_USERNAME"] 8 | # Add application configuration variables here, as shown below. 9 | # 10 | MANDRILL_USERNAME: Your_Username 11 | MANDRILL_API_KEY: Your_Mandrill_API_Key 12 | MAILCHIMP_API_KEY: Your_MailChimp_API_Key 13 | MAILCHIMP_LIST_ID: My_List_ID 14 | ADMIN_NAME: First User 15 | ADMIN_EMAIL: user@example.com 16 | ADMIN_PASSWORD: changeme 17 | ROLES: [admin, user] 18 | EMAIL_ADDRESS: user@example.com 19 | DOMAIN: example.com 20 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | # Pick the frameworks you want: 4 | require "active_record/railtie" 5 | require "action_controller/railtie" 6 | require "action_mailer/railtie" 7 | require "active_resource/railtie" 8 | require "sprockets/railtie" 9 | # require "rails/test_unit/railtie" 10 | 11 | if defined?(Bundler) 12 | # If you precompile assets before deploying to production, use this line 13 | Bundler.require(*Rails.groups(:assets => %w(development test))) 14 | # If you want your assets lazily compiled in production, use this line 15 | # Bundler.require(:default, :assets, Rails.env) 16 | end 17 | 18 | module RailsPrelaunchSignup 19 | class Application < Rails::Application 20 | 21 | # don't generate RSpec tests for views and helpers 22 | config.generators do |g| 23 | 24 | g.test_framework :rspec, fixture: true 25 | g.fixture_replacement :factory_girl, dir: 'spec/factories' 26 | 27 | 28 | g.view_specs false 29 | g.helper_specs false 30 | end 31 | 32 | # Settings in config/environments/* take precedence over those specified here. 33 | # Application configuration should go into files in config/initializers 34 | # -- all .rb files in that directory are automatically loaded. 35 | 36 | # Custom directories with classes and modules you want to be autoloadable. 37 | # config.autoload_paths += %W(#{config.root}/extras) 38 | config.autoload_paths += %W(#{config.root}/lib) 39 | 40 | 41 | # Only load the plugins named here, in the order given (default is alphabetical). 42 | # :all can be used as a placeholder for all plugins not explicitly named. 43 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 44 | 45 | # Activate observers that should always be running. 46 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 47 | 48 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 49 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 50 | # config.time_zone = 'Central Time (US & Canada)' 51 | 52 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 53 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 54 | # config.i18n.default_locale = :de 55 | 56 | # Configure the default encoding used in templates for Ruby 1.9. 57 | config.encoding = "utf-8" 58 | 59 | # Configure sensitive parameters which will be filtered from the log file. 60 | config.filter_parameters += [:password, :password_confirmation] 61 | 62 | # Enable escaping HTML in JSON. 63 | config.active_support.escape_html_entities_in_json = true 64 | 65 | # Use SQL instead of Active Record's schema dumper when creating the database. 66 | # This is necessary if your schema can't be completely dumped by the schema dumper, 67 | # like if you have constraints or database-specific column types 68 | # config.active_record.schema_format = :sql 69 | 70 | # Enforce whitelist mode for mass assignment. 71 | # This will create an empty whitelist of attributes available for mass-assignment for all models 72 | # in your app. As such, your models will need to explicitly whitelist or blacklist accessible 73 | # parameters by using an attr_accessible or attr_protected declaration. 74 | config.active_record.whitelist_attributes = true 75 | 76 | # Enable the asset pipeline 77 | config.assets.enabled = true 78 | 79 | # Version of your assets, change this if you want to expire all your assets 80 | config.assets.version = '1.0' 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /config/application.yml: -------------------------------------------------------------------------------- 1 | # Add account credentials and API keys here. 2 | # See http://railsapps.github.io/rails-environment-variables.html 3 | # This file should be listed in .gitignore to keep your settings secret! 4 | # Each entry sets a local environment variable and overrides ENV variables in the Unix shell. 5 | # For example, setting: 6 | # GMAIL_USERNAME: Your_Gmail_Username 7 | # makes 'Your_Gmail_Username' available as ENV["GMAIL_USERNAME"] 8 | # Add application configuration variables here, as shown below. 9 | # 10 | MANDRILL_USERNAME: Your_Username 11 | MANDRILL_API_KEY: Your_Mandrill_API_Key 12 | MAILCHIMP_API_KEY: Your_MailChimp_API_Key 13 | MAILCHIMP_LIST_ID: My_List_ID 14 | ADMIN_NAME: First User 15 | ADMIN_EMAIL: user@example.com 16 | ADMIN_PASSWORD: changeme 17 | ROLES: [admin, user] 18 | EMAIL_ADDRESS: user@example.com 19 | DOMAIN: example.com 20 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /config/cucumber.yml: -------------------------------------------------------------------------------- 1 | <% 2 | rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" 3 | rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" 4 | std_opts = "-r features/support/ -r features/step_definitions --format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip" 5 | %> 6 | default: <%= std_opts %> features 7 | wip: --tags @wip:3 --wip features 8 | rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip 9 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: sqlite3 8 | database: db/development.sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | # Warning: The database defined as "test" will be erased and 13 | # re-generated from your development database when you run "rake". 14 | # Do not set this db to the same as development or production. 15 | test: &test 16 | adapter: sqlite3 17 | database: db/test.sqlite3 18 | pool: 5 19 | timeout: 5000 20 | 21 | production: 22 | adapter: sqlite3 23 | database: db/production.sqlite3 24 | pool: 5 25 | timeout: 5000 26 | 27 | cucumber: 28 | <<: *test -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | RailsPrelaunchSignup::Application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | RailsPrelaunchSignup::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # ActionMailer Config 17 | config.action_mailer.default_url_options = { :host => 'localhost:3000' } 18 | config.action_mailer.delivery_method = :smtp 19 | # change to true to allow email to be sent during development 20 | config.action_mailer.perform_deliveries = false 21 | config.action_mailer.raise_delivery_errors = true 22 | config.action_mailer.default :charset => "utf-8" 23 | 24 | config.action_mailer.smtp_settings = { 25 | :address => "smtp.mandrillapp.com", 26 | :port => 25, 27 | :user_name => ENV["MANDRILL_USERNAME"], 28 | :password => ENV["MANDRILL_API_KEY"] 29 | } 30 | 31 | 32 | 33 | # Print deprecation notices to the Rails logger 34 | config.active_support.deprecation = :log 35 | 36 | # Only use best-standards-support built into browsers 37 | config.action_dispatch.best_standards_support = :builtin 38 | 39 | # Raise exception on mass assignment protection for Active Record models 40 | config.active_record.mass_assignment_sanitizer = :strict 41 | 42 | # Log the query plan for queries taking more than this (works 43 | # with SQLite, MySQL, and PostgreSQL) 44 | config.active_record.auto_explain_threshold_in_seconds = 0.5 45 | 46 | # Do not compress assets 47 | config.assets.compress = false 48 | 49 | # Expands the lines which load the assets 50 | config.assets.debug = true 51 | end 52 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | RailsPrelaunchSignup::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to nil and saved in location specified by config.assets.prefix 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Prepend all log lines with the following tags 37 | # config.log_tags = [ :subdomain, :uuid ] 38 | 39 | # Use a different logger for distributed setups 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 41 | 42 | # Use a different cache store in production 43 | # config.cache_store = :mem_cache_store 44 | 45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 46 | # config.action_controller.asset_host = "http://assets.example.com" 47 | 48 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 49 | # config.assets.precompile += %w( search.js ) 50 | 51 | # Disable delivery errors, bad email addresses will be ignored 52 | # config.action_mailer.raise_delivery_errors = false 53 | 54 | # Enable threaded mode 55 | # config.threadsafe! 56 | 57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 58 | # the I18n.default_locale when a translation can not be found) 59 | config.i18n.fallbacks = true 60 | 61 | # Send deprecation notices to registered listeners 62 | config.active_support.deprecation = :notify 63 | 64 | config.action_mailer.default_url_options = { :host => 'example.com' } 65 | # ActionMailer Config 66 | # Setup for production - deliveries, no errors raised 67 | config.action_mailer.delivery_method = :smtp 68 | config.action_mailer.perform_deliveries = true 69 | config.action_mailer.raise_delivery_errors = false 70 | config.action_mailer.default :charset => "utf-8" 71 | 72 | config.action_mailer.smtp_settings = { 73 | :address => "smtp.mandrillapp.com", 74 | :port => 25, 75 | :user_name => ENV["MANDRILL_USERNAME"], 76 | :password => ENV["MANDRILL_API_KEY"] 77 | } 78 | 79 | 80 | 81 | # Log the query plan for queries taking more than this (works 82 | # with SQLite, MySQL, and PostgreSQL) 83 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 84 | end 85 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | RailsPrelaunchSignup::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Raise exception on mass assignment protection for Active Record models 33 | config.active_record.mass_assignment_sanitizer = :strict 34 | 35 | # Print deprecation notices to the stderr 36 | config.active_support.deprecation = :stderr 37 | 38 | # ActionMailer Config 39 | config.action_mailer.default_url_options = { :host => 'example.com' } 40 | 41 | end 42 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/devise.rb: -------------------------------------------------------------------------------- 1 | # Use this hook to configure devise mailer, warden hooks and so forth. 2 | # Many of these configuration options can be set straight in your model. 3 | Devise.setup do |config| 4 | # ==> Mailer Configuration 5 | # Configure the e-mail address which will be shown in Devise::Mailer, 6 | # note that it will be overwritten if you use your own mailer class with default "from" parameter. 7 | config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com" 8 | 9 | # Configure the class responsible to send e-mails. 10 | # config.mailer = "Devise::Mailer" 11 | 12 | # ==> ORM configuration 13 | # Load and configure the ORM. Supports :active_record (default) and 14 | # :mongoid (bson_ext recommended) by default. Other ORMs may be 15 | # available as additional gems. 16 | require 'devise/orm/active_record' 17 | 18 | # ==> Configuration for any authentication mechanism 19 | # Configure which keys are used when authenticating a user. The default is 20 | # just :email. You can configure it to use [:username, :subdomain], so for 21 | # authenticating a user, both parameters are required. Remember that those 22 | # parameters are used only when authenticating and not when retrieving from 23 | # session. If you need permissions, you should implement that in a before filter. 24 | # You can also supply a hash where the value is a boolean determining whether 25 | # or not authentication should be aborted when the value is not present. 26 | # config.authentication_keys = [ :email ] 27 | 28 | # Configure parameters from the request object used for authentication. Each entry 29 | # given should be a request method and it will automatically be passed to the 30 | # find_for_authentication method and considered in your model lookup. For instance, 31 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. 32 | # The same considerations mentioned for authentication_keys also apply to request_keys. 33 | # config.request_keys = [] 34 | 35 | # Configure which authentication keys should be case-insensitive. 36 | # These keys will be downcased upon creating or modifying a user and when used 37 | # to authenticate or find a user. Default is :email. 38 | config.case_insensitive_keys = [ :email ] 39 | 40 | # Configure which authentication keys should have whitespace stripped. 41 | # These keys will have whitespace before and after removed upon creating or 42 | # modifying a user and when used to authenticate or find a user. Default is :email. 43 | config.strip_whitespace_keys = [ :email ] 44 | 45 | # Tell if authentication through request.params is enabled. True by default. 46 | # It can be set to an array that will enable params authentication only for the 47 | # given strategies, for example, `config.params_authenticatable = [:database]` will 48 | # enable it only for database (email + password) authentication. 49 | # config.params_authenticatable = true 50 | 51 | # Tell if authentication through HTTP Auth is enabled. False by default. 52 | # It can be set to an array that will enable http authentication only for the 53 | # given strategies, for example, `config.http_authenticatable = [:token]` will 54 | # enable it only for token authentication. The supported strategies are: 55 | # :database = Support basic authentication with authentication key + password 56 | # :token = Support basic authentication with token authentication key 57 | # :token_options = Support token authentication with options as defined in 58 | # http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html 59 | # config.http_authenticatable = false 60 | 61 | # If http headers should be returned for AJAX requests. True by default. 62 | # config.http_authenticatable_on_xhr = true 63 | 64 | # The realm used in Http Basic Authentication. "Application" by default. 65 | # config.http_authentication_realm = "Application" 66 | 67 | # It will change confirmation, password recovery and other workflows 68 | # to behave the same regardless if the e-mail provided was right or wrong. 69 | # Does not affect registerable. 70 | # config.paranoid = true 71 | 72 | # By default Devise will store the user in session. You can skip storage for 73 | # :http_auth and :token_auth by adding those symbols to the array below. 74 | # Notice that if you are skipping storage for all authentication paths, you 75 | # may want to disable generating routes to Devise's sessions controller by 76 | # passing :skip => :sessions to `devise_for` in your config/routes.rb 77 | config.skip_session_storage = [:http_auth] 78 | 79 | # ==> Configuration for :database_authenticatable 80 | # For bcrypt, this is the cost for hashing the password and defaults to 10. If 81 | # using other encryptors, it sets how many times you want the password re-encrypted. 82 | # 83 | # Limiting the stretches to just one in testing will increase the performance of 84 | # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use 85 | # a value less than 10 in other environments. 86 | config.stretches = Rails.env.test? ? 1 : 10 87 | 88 | # Setup a pepper to generate the encrypted password. 89 | # config.pepper = "880d20a22e1f588255c5262fb34440ef72d7bd201c65e79677e74c108ebf6482f55177d2bbf13e6ef3957676c36981093e584e7634221207409e0c420325a77e" 90 | 91 | # ==> Configuration for :confirmable 92 | # A period that the user is allowed to access the website even without 93 | # confirming his account. For instance, if set to 2.days, the user will be 94 | # able to access the website for two days without confirming his account, 95 | # access will be blocked just in the third day. Default is 0.days, meaning 96 | # the user cannot access the website without confirming his account. 97 | # config.allow_unconfirmed_access_for = 2.days 98 | 99 | # A period that the user is allowed to confirm their account before their 100 | # token becomes invalid. For example, if set to 3.days, the user can confirm 101 | # their account within 3 days after the mail was sent, but on the fourth day 102 | # their account can't be confirmed with the token any more. 103 | # Default is nil, meaning there is no restriction on how long a user can take 104 | # before confirming their account. 105 | # config.confirm_within = 3.days 106 | 107 | # If true, requires any email changes to be confirmed (exactly the same way as 108 | # initial account confirmation) to be applied. Requires additional unconfirmed_email 109 | # db field (see migrations). Until confirmed new email is stored in 110 | # unconfirmed email column, and copied to email column on successful confirmation. 111 | config.reconfirmable = true 112 | 113 | # Defines which key will be used when confirming an account 114 | # config.confirmation_keys = [ :email ] 115 | 116 | # ==> Configuration for :rememberable 117 | # The time the user will be remembered without asking for credentials again. 118 | # config.remember_for = 2.weeks 119 | 120 | # If true, extends the user's remember period when remembered via cookie. 121 | # config.extend_remember_period = false 122 | 123 | # Options to be passed to the created cookie. For instance, you can set 124 | # :secure => true in order to force SSL only cookies. 125 | # config.rememberable_options = {} 126 | 127 | # ==> Configuration for :validatable 128 | # Range for password length. Default is 8..128. 129 | config.password_length = 8..128 130 | 131 | # Email regex used to validate email formats. It simply asserts that 132 | # one (and only one) @ exists in the given string. This is mainly 133 | # to give user feedback and not to assert the e-mail validity. 134 | # config.email_regexp = /\A[^@]+@[^@]+\z/ 135 | 136 | # ==> Configuration for :timeoutable 137 | # The time you want to timeout the user session without activity. After this 138 | # time the user will be asked for credentials again. Default is 30 minutes. 139 | # config.timeout_in = 30.minutes 140 | 141 | # If true, expires auth token on session timeout. 142 | # config.expire_auth_token_on_timeout = false 143 | 144 | # ==> Configuration for :lockable 145 | # Defines which strategy will be used to lock an account. 146 | # :failed_attempts = Locks an account after a number of failed attempts to sign in. 147 | # :none = No lock strategy. You should handle locking by yourself. 148 | # config.lock_strategy = :failed_attempts 149 | 150 | # Defines which key will be used when locking and unlocking an account 151 | # config.unlock_keys = [ :email ] 152 | 153 | # Defines which strategy will be used to unlock an account. 154 | # :email = Sends an unlock link to the user email 155 | # :time = Re-enables login after a certain amount of time (see :unlock_in below) 156 | # :both = Enables both strategies 157 | # :none = No unlock strategy. You should handle unlocking by yourself. 158 | # config.unlock_strategy = :both 159 | 160 | # Number of authentication tries before locking an account if lock_strategy 161 | # is failed attempts. 162 | # config.maximum_attempts = 20 163 | 164 | # Time interval to unlock the account if :time is enabled as unlock_strategy. 165 | # config.unlock_in = 1.hour 166 | 167 | # ==> Configuration for :recoverable 168 | # 169 | # Defines which key will be used when recovering the password for an account 170 | # config.reset_password_keys = [ :email ] 171 | 172 | # Time interval you can reset your password with a reset password key. 173 | # Don't put a too small interval or your users won't have the time to 174 | # change their passwords. 175 | config.reset_password_within = 6.hours 176 | 177 | # ==> Configuration for :encryptable 178 | # Allow you to use another encryption algorithm besides bcrypt (default). You can use 179 | # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, 180 | # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) 181 | # and :restful_authentication_sha1 (then you should set stretches to 10, and copy 182 | # REST_AUTH_SITE_KEY to pepper). 183 | # 184 | # Require the `devise-encryptable` gem when using anything other than bcrypt 185 | # config.encryptor = :sha512 186 | 187 | # ==> Configuration for :token_authenticatable 188 | # Defines name of the authentication token params key 189 | # config.token_authentication_key = :auth_token 190 | 191 | # ==> Scopes configuration 192 | # Turn scoped views on. Before rendering "sessions/new", it will first check for 193 | # "users/sessions/new". It's turned off by default because it's slower if you 194 | # are using only default views. 195 | # config.scoped_views = false 196 | 197 | # Configure the default scope given to Warden. By default it's the first 198 | # devise role declared in your routes (usually :user). 199 | # config.default_scope = :user 200 | 201 | # Set this configuration to false if you want /users/sign_out to sign out 202 | # only the current scope. By default, Devise signs out all scopes. 203 | # config.sign_out_all_scopes = true 204 | 205 | # ==> Navigation configuration 206 | # Lists the formats that should be treated as navigational. Formats like 207 | # :html, should redirect to the sign in page when the user does not have 208 | # access, but formats like :xml or :json, should return 401. 209 | # 210 | # If you have any extra navigational formats, like :iphone or :mobile, you 211 | # should add them to the navigational formats lists. 212 | # 213 | # The "*/*" below is required to match Internet Explorer requests. 214 | # config.navigational_formats = ["*/*", :html] 215 | 216 | # The default HTTP method used to sign out a resource. Default is :delete. 217 | config.sign_out_via = Rails.env.test? ? :get : :delete 218 | 219 | # ==> OmniAuth 220 | # Add a new OmniAuth provider. Check the wiki for more information on setting 221 | # up on your models and hooks. 222 | # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' 223 | 224 | # ==> Warden configuration 225 | # If you want to use other strategies, that are not supported by Devise, or 226 | # change the failure app, you can configure them inside the config.warden block. 227 | # 228 | # config.warden do |manager| 229 | # manager.intercept_401 = false 230 | # manager.default_strategies(:scope => :user).unshift :some_external_strategy 231 | # end 232 | 233 | # ==> Mountable engine configurations 234 | # When using Devise inside an engine, let's call it `MyEngine`, and this engine 235 | # is mountable, there are some extra configurations to be taken into account. 236 | # The following options are available, assuming the engine is mounted as: 237 | # 238 | # mount MyEngine, at: "/my_engine" 239 | # 240 | # The router that invoked `devise_for`, in the example above, would be: 241 | # config.router_name = :my_engine 242 | # 243 | # When using omniauth, Devise cannot automatically set Omniauth path, 244 | # so you need to do it manually. For the users scope, it would be: 245 | # config.omniauth_path_prefix = "/my_engine/users/auth" 246 | end 247 | -------------------------------------------------------------------------------- /config/initializers/generators.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.generators do |g| 2 | end 3 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | # 12 | # These inflection rules are supported but not enabled by default: 13 | # ActiveSupport::Inflector.inflections do |inflect| 14 | # inflect.acronym 'RESTful' 15 | # end 16 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /config/initializers/rolify.rb: -------------------------------------------------------------------------------- 1 | Rolify.configure do |config| 2 | # By default ORM adapter is ActiveRecord. uncomment to use mongoid 3 | # config.use_mongoid 4 | 5 | # Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false 6 | # Enable this feature _after_ running rake db:migrate as it relies on the roles table 7 | # config.use_dynamic_shortcuts 8 | end -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | RailsPrelaunchSignup::Application.config.secret_token = '1ba85dd1130cb8eed4b810a598d953d218b51c7a05503474fe24eac65df0f9d9f828a59dcc5adbf1183fba51dcadda34832e04bbd31b44854de0dd3f8cabf45a' 8 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | RailsPrelaunchSignup::Application.config.session_store :cookie_store, key: '_rails-prelaunch-signup_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # RailsPrelaunchSignup::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /config/initializers/simple_form.rb: -------------------------------------------------------------------------------- 1 | # Use this setup block to configure all options available in SimpleForm. 2 | SimpleForm.setup do |config| 3 | # Wrappers are used by the form builder to generate a 4 | # complete input. You can remove any component from the 5 | # wrapper, change the order or even add your own to the 6 | # stack. The options given below are used to wrap the 7 | # whole input. 8 | config.wrappers :default, :class => :input, 9 | :hint_class => :field_with_hint, :error_class => :field_with_errors do |b| 10 | ## Extensions enabled by default 11 | # Any of these extensions can be disabled for a 12 | # given input by passing: `f.input EXTENSION_NAME => false`. 13 | # You can make any of these extensions optional by 14 | # renaming `b.use` to `b.optional`. 15 | 16 | # Determines whether to use HTML5 (:email, :url, ...) 17 | # and required attributes 18 | b.use :html5 19 | 20 | # Calculates placeholders automatically from I18n 21 | # You can also pass a string as f.input :placeholder => "Placeholder" 22 | b.use :placeholder 23 | 24 | ## Optional extensions 25 | # They are disabled unless you pass `f.input EXTENSION_NAME => :lookup` 26 | # to the input. If so, they will retrieve the values from the model 27 | # if any exists. If you want to enable the lookup for any of those 28 | # extensions by default, you can change `b.optional` to `b.use`. 29 | 30 | # Calculates maxlength from length validations for string inputs 31 | b.optional :maxlength 32 | 33 | # Calculates pattern from format validations for string inputs 34 | b.optional :pattern 35 | 36 | # Calculates min and max from length validations for numeric inputs 37 | b.optional :min_max 38 | 39 | # Calculates readonly automatically from readonly attributes 40 | b.optional :readonly 41 | 42 | ## Inputs 43 | b.use :label_input 44 | b.use :hint, :wrap_with => { :tag => :span, :class => :hint } 45 | b.use :error, :wrap_with => { :tag => :span, :class => :error } 46 | end 47 | 48 | # The default wrapper to be used by the FormBuilder. 49 | config.default_wrapper = :default 50 | 51 | # Define the way to render check boxes / radio buttons with labels. 52 | # Defaults to :nested for bootstrap config. 53 | # :inline => input + label 54 | # :nested => label > input 55 | config.boolean_style = :nested 56 | 57 | # Default class for buttons 58 | config.button_class = 'btn' 59 | 60 | # Method used to tidy up errors. Specify any Rails Array method. 61 | # :first lists the first message for each field. 62 | # Use :to_sentence to list all errors for each field. 63 | # config.error_method = :first 64 | 65 | # Default tag used for error notification helper. 66 | config.error_notification_tag = :div 67 | 68 | # CSS class to add for error notification helper. 69 | config.error_notification_class = 'alert alert-error' 70 | 71 | # ID to add for error notification helper. 72 | # config.error_notification_id = nil 73 | 74 | # Series of attempts to detect a default label method for collection. 75 | # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] 76 | 77 | # Series of attempts to detect a default value method for collection. 78 | # config.collection_value_methods = [ :id, :to_s ] 79 | 80 | # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. 81 | # config.collection_wrapper_tag = nil 82 | 83 | # You can define the class to use on all collection wrappers. Defaulting to none. 84 | # config.collection_wrapper_class = nil 85 | 86 | # You can wrap each item in a collection of radio/check boxes with a tag, 87 | # defaulting to :span. Please note that when using :boolean_style = :nested, 88 | # SimpleForm will force this option to be a label. 89 | # config.item_wrapper_tag = :span 90 | 91 | # You can define a class to use in all item wrappers. Defaulting to none. 92 | # config.item_wrapper_class = nil 93 | 94 | # How the label text should be generated altogether with the required text. 95 | # config.label_text = lambda { |label, required| "#{required} #{label}" } 96 | 97 | # You can define the class to use on all labels. Default is nil. 98 | config.label_class = 'control-label' 99 | 100 | # You can define the class to use on all forms. Default is simple_form. 101 | # config.form_class = :simple_form 102 | 103 | # You can define which elements should obtain additional classes 104 | # config.generate_additional_classes_for = [:wrapper, :label, :input] 105 | 106 | # Whether attributes are required by default (or not). Default is true. 107 | # config.required_by_default = true 108 | 109 | # Tell browsers whether to use default HTML5 validations (novalidate option). 110 | # Default is enabled. 111 | config.browser_validations = false 112 | 113 | # Collection of methods to detect if a file type was given. 114 | # config.file_methods = [ :mounted_as, :file?, :public_filename ] 115 | 116 | # Custom mappings for input types. This should be a hash containing a regexp 117 | # to match as key, and the input type that will be used when the field name 118 | # matches the regexp as value. 119 | # config.input_mappings = { /count/ => :integer } 120 | 121 | # Custom wrappers for input types. This should be a hash containing an input 122 | # type as key and the wrapper that will be used for all inputs with specified type. 123 | # config.wrapper_mappings = { :string => :prepend } 124 | 125 | # Default priority for time_zone inputs. 126 | # config.time_zone_priority = nil 127 | 128 | # Default priority for country inputs. 129 | # config.country_priority = nil 130 | 131 | # Default size for text inputs. 132 | # config.default_input_size = 50 133 | 134 | # When false, do not use translations for labels. 135 | # config.translate_labels = true 136 | 137 | # Automatically discover new inputs in Rails' autoload path. 138 | # config.inputs_discovery = true 139 | 140 | # Cache SimpleForm inputs discovery 141 | # config.cache_discovery = !Rails.env.development? 142 | end 143 | -------------------------------------------------------------------------------- /config/initializers/simple_form_bootstrap.rb: -------------------------------------------------------------------------------- 1 | # Use this setup block to configure all options available in SimpleForm. 2 | SimpleForm.setup do |config| 3 | config.wrappers :bootstrap, :tag => 'div', :class => 'control-group', :error_class => 'error' do |b| 4 | b.use :html5 5 | b.use :placeholder 6 | b.use :label 7 | b.wrapper :tag => 'div', :class => 'controls' do |ba| 8 | ba.use :input 9 | ba.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' } 10 | ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' } 11 | end 12 | end 13 | 14 | config.wrappers :prepend, :tag => 'div', :class => "control-group", :error_class => 'error' do |b| 15 | b.use :html5 16 | b.use :placeholder 17 | b.use :label 18 | b.wrapper :tag => 'div', :class => 'controls' do |input| 19 | input.wrapper :tag => 'div', :class => 'input-prepend' do |prepend| 20 | prepend.use :input 21 | end 22 | input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' } 23 | input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' } 24 | end 25 | end 26 | 27 | config.wrappers :append, :tag => 'div', :class => "control-group", :error_class => 'error' do |b| 28 | b.use :html5 29 | b.use :placeholder 30 | b.use :label 31 | b.wrapper :tag => 'div', :class => 'controls' do |input| 32 | input.wrapper :tag => 'div', :class => 'input-append' do |append| 33 | append.use :input 34 | end 35 | input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' } 36 | input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' } 37 | end 38 | end 39 | 40 | # Wrappers for forms and inputs using the Twitter Bootstrap toolkit. 41 | # Check the Bootstrap docs (http://twitter.github.com/bootstrap) 42 | # to learn about the different styles for forms and inputs, 43 | # buttons and other elements. 44 | config.default_wrapper = :bootstrap 45 | end 46 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /config/locales/devise.en.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n 2 | 3 | en: 4 | devise: 5 | confirmations: 6 | confirmed: "Your account was successfully confirmed. You are now signed in." 7 | send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." 8 | send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes." 9 | failure: 10 | already_authenticated: "You are already signed in." 11 | inactive: "Your account was not activated yet." 12 | invalid: "Invalid email or password." 13 | invalid_token: "Invalid authentication token." 14 | locked: "Your account is locked." 15 | not_found_in_database: "Invalid email or password." 16 | timeout: "Your session expired, please sign in again to continue." 17 | unauthenticated: "You need to sign in or sign up before continuing." 18 | unconfirmed: 'Your account is not active.' 19 | mailer: 20 | confirmation_instructions: 21 | subject: "Confirmation instructions" 22 | reset_password_instructions: 23 | subject: "Reset password instructions" 24 | unlock_instructions: 25 | subject: "Unlock Instructions" 26 | omniauth_callbacks: 27 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"." 28 | success: "Successfully authenticated from %{kind} account." 29 | passwords: 30 | no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." 31 | send_instructions: "You will receive an email with instructions about how to reset your password in a few minutes." 32 | send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." 33 | updated: "Your password was changed successfully. You are now signed in." 34 | updated_not_active: "Your password was changed successfully." 35 | registrations: 36 | destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon." 37 | signed_up: "Welcome! You have signed up successfully." 38 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." 39 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." 40 | signed_up_but_unconfirmed: 'Your invitation request has been received. You will receive an invitation when we launch.' 41 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address." 42 | updated: "You updated your account successfully." 43 | sessions: 44 | signed_in: "Signed in successfully." 45 | signed_out: "Signed out successfully." 46 | unlocks: 47 | send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes." 48 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes." 49 | unlocked: "Your account has been unlocked successfully. Please sign in to continue." 50 | errors: 51 | messages: 52 | already_confirmed: "was already confirmed, please try signing in" 53 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" 54 | expired: "has expired, please request a new one" 55 | not_found: "not found" 56 | not_locked: "was not locked" 57 | not_saved: 58 | one: "1 error prohibited this %{resource} from being saved:" 59 | other: "%{count} errors prohibited this %{resource} from being saved:" 60 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /config/locales/simple_form.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | simple_form: 3 | "yes": 'Yes' 4 | "no": 'No' 5 | required: 6 | text: 'required' 7 | mark: '*' 8 | # You can uncomment the line below if you need to overwrite the whole required html. 9 | # When using html, text and mark won't be used. 10 | # html: '*' 11 | error_notification: 12 | default_message: "Please review the problems below:" 13 | # Labels and hints examples 14 | # labels: 15 | # defaults: 16 | # password: 'Password' 17 | # user: 18 | # new: 19 | # email: 'E-mail to sign in.' 20 | # edit: 21 | # email: 'E-mail.' 22 | # hints: 23 | # defaults: 24 | # username: 'User name to sign in.' 25 | # password: 'No special characters, please.' 26 | 27 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | RailsPrelaunchSignup::Application.routes.draw do 2 | authenticated :user do 3 | root :to => 'home#index' 4 | end 5 | devise_scope :user do 6 | root :to => "devise/registrations#new" 7 | match '/user/confirmation' => 'confirmations#update', :via => :put, :as => :update_user_confirmation 8 | end 9 | devise_for :users, :controllers => { :registrations => "registrations", :confirmations => "confirmations" } 10 | match 'users/bulk_invite/:quantity' => 'users#bulk_invite', :via => :get, :as => :bulk_invite 11 | resources :users do 12 | get 'invite', :on => :member 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20120826102841_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table(:users) do |t| 4 | ## Database authenticatable 5 | t.string :email, :null => false, :default => "" 6 | t.string :encrypted_password, :null => false, :default => "" 7 | 8 | ## Recoverable 9 | t.string :reset_password_token 10 | t.datetime :reset_password_sent_at 11 | 12 | ## Rememberable 13 | t.datetime :remember_created_at 14 | 15 | ## Trackable 16 | t.integer :sign_in_count, :default => 0 17 | t.datetime :current_sign_in_at 18 | t.datetime :last_sign_in_at 19 | t.string :current_sign_in_ip 20 | t.string :last_sign_in_ip 21 | 22 | ## Confirmable 23 | # t.string :confirmation_token 24 | # t.datetime :confirmed_at 25 | # t.datetime :confirmation_sent_at 26 | # t.string :unconfirmed_email # Only if using reconfirmable 27 | 28 | ## Lockable 29 | # t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts 30 | # t.string :unlock_token # Only if unlock strategy is :email or :both 31 | # t.datetime :locked_at 32 | 33 | ## Token authenticatable 34 | # t.string :authentication_token 35 | 36 | 37 | t.timestamps 38 | end 39 | 40 | add_index :users, :email, :unique => true 41 | add_index :users, :reset_password_token, :unique => true 42 | # add_index :users, :confirmation_token, :unique => true 43 | # add_index :users, :unlock_token, :unique => true 44 | # add_index :users, :authentication_token, :unique => true 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /db/migrate/20120826102844_add_name_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddNameToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120826102849_add_confirmable_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddConfirmableToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :confirmation_token, :string 4 | add_column :users, :confirmed_at, :datetime 5 | add_column :users, :confirmation_sent_at, :datetime 6 | add_column :users, :unconfirmed_email, :string 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20120826102855_rolify_create_roles.rb: -------------------------------------------------------------------------------- 1 | class RolifyCreateRoles < ActiveRecord::Migration 2 | def change 3 | create_table(:roles) do |t| 4 | t.string :name 5 | t.references :resource, :polymorphic => true 6 | 7 | t.timestamps 8 | end 9 | 10 | create_table(:users_roles, :id => false) do |t| 11 | t.references :user 12 | t.references :role 13 | end 14 | 15 | add_index(:roles, :name) 16 | add_index(:roles, [ :name, :resource_type, :resource_id ]) 17 | add_index(:users_roles, [ :user_id, :role_id ]) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20120826102940) do 15 | 16 | create_table "roles", :force => true do |t| 17 | t.string "name" 18 | t.integer "resource_id" 19 | t.string "resource_type" 20 | t.datetime "created_at", :null => false 21 | t.datetime "updated_at", :null => false 22 | end 23 | 24 | add_index "roles", ["name", "resource_type", "resource_id"], :name => "index_roles_on_name_and_resource_type_and_resource_id" 25 | add_index "roles", ["name"], :name => "index_roles_on_name" 26 | 27 | create_table "users", :force => true do |t| 28 | t.string "email", :default => "", :null => false 29 | t.string "encrypted_password", :default => "", :null => false 30 | t.string "reset_password_token" 31 | t.datetime "reset_password_sent_at" 32 | t.datetime "remember_created_at" 33 | t.integer "sign_in_count", :default => 0 34 | t.datetime "current_sign_in_at" 35 | t.datetime "last_sign_in_at" 36 | t.string "current_sign_in_ip" 37 | t.string "last_sign_in_ip" 38 | t.datetime "created_at", :null => false 39 | t.datetime "updated_at", :null => false 40 | t.string "name" 41 | t.string "confirmation_token" 42 | t.datetime "confirmed_at" 43 | t.datetime "confirmation_sent_at" 44 | t.string "unconfirmed_email" 45 | end 46 | 47 | add_index "users", ["email"], :name => "index_users_on_email", :unique => true 48 | add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true 49 | 50 | create_table "users_roles", :id => false, :force => true do |t| 51 | t.integer "user_id" 52 | t.integer "role_id" 53 | end 54 | 55 | add_index "users_roles", ["user_id", "role_id"], :name => "index_users_roles_on_user_id_and_role_id" 56 | 57 | end 58 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | # Environment variables (ENV['...']) are set in the file config/application.yml. 9 | # See http://railsapps.github.io/rails-environment-variables.html 10 | puts 'ROLES' 11 | YAML.load(ENV['ROLES']).each do |role| 12 | Role.find_or_create_by_name({ :name => role }, :without_protection => true) 13 | puts 'role: ' << role 14 | end 15 | puts 'DEFAULT USERS' 16 | user = User.find_or_create_by_email :name => ENV['ADMIN_NAME'].dup, :email => ENV['ADMIN_EMAIL'].dup, :password => ENV['ADMIN_PASSWORD'].dup, :password_confirmation => ENV['ADMIN_PASSWORD'].dup 17 | puts 'user: ' << user.name 18 | user.add_role :admin 19 | user.skip_confirmation! 20 | user.save! 21 | -------------------------------------------------------------------------------- /features/admin/send_invitations.feature: -------------------------------------------------------------------------------- 1 | @javascript 2 | Feature: Send Invitations 3 | As the owner of the site 4 | I want to send invitations to visitors who have requested invitations 5 | so users can try the site 6 | 7 | Scenario: Administrator sends invitation 8 | Given I am not logged in 9 | When I visit the home page 10 | And I follow "Request invite" 11 | When I fill in "Email" with "example@example.com" 12 | And I click a button "Request Invitation" 13 | Then I should see a message "Thank you!" 14 | When I am logged in as an administrator 15 | And I visit the users page 16 | When I click a link "send invitation" 17 | Then I should see "Sent invitation to example@example.com" 18 | When I open the email with subject "Confirmation instructions" 19 | Then I should see "confirm your email address" in the email body 20 | -------------------------------------------------------------------------------- /features/admin/view_progress.feature: -------------------------------------------------------------------------------- 1 | Feature: View Progress 2 | As the owner of the site 3 | I want to know how many visitors have requested invitations 4 | so I can know if my offer is popular 5 | 6 | @javascript 7 | Scenario: Administrator views list of users 8 | Given I am not logged in 9 | When I visit the home page 10 | And I follow "Request invite" 11 | When I fill in "Email" with "example@example.com" 12 | And I click a button "Request Invitation" 13 | Then I should see a message "Thank you!" 14 | When I am logged in as an administrator 15 | And I visit the users page 16 | Then I should see "example@example.com" 17 | 18 | Scenario: User cannot view list of users 19 | Given I am logged in 20 | When I visit the users page 21 | Then I should see an access denied message 22 | -------------------------------------------------------------------------------- /features/step_definitions/admin_steps.rb: -------------------------------------------------------------------------------- 1 | Given /^I am logged in as an administrator$/ do 2 | @admin = FactoryGirl.create(:user, email: "admin@example.com") 3 | @admin.add_role :admin 4 | @visitor ||= { :email => "admin@example.com", 5 | :password => "changeme", :password_confirmation => "changeme" } 6 | sign_in 7 | end 8 | 9 | When /^I visit the users page$/ do 10 | visit users_path 11 | end 12 | 13 | When /^I click a link "([^"]*)"$/ do |arg1| 14 | click_on (arg1) 15 | end 16 | 17 | Then /^I should see a list of users$/ do 18 | page.should have_content @user[:email] 19 | end 20 | 21 | Then /^I should see an access denied message$/ do 22 | page.should have_content "Not authorized as an administrator" 23 | end 24 | 25 | Then /^show me the page$/ do 26 | save_and_open_page 27 | end 28 | 29 | Then /^I should see "(.*?)"$/ do |text| 30 | page.should have_content(text) 31 | end 32 | -------------------------------------------------------------------------------- /features/step_definitions/email_steps.rb: -------------------------------------------------------------------------------- 1 | # Commonly used email steps 2 | # 3 | # To add your own steps make a custom_email_steps.rb 4 | # The provided methods are: 5 | # 6 | # last_email_address 7 | # reset_mailer 8 | # open_last_email 9 | # visit_in_email 10 | # unread_emails_for 11 | # mailbox_for 12 | # current_email 13 | # open_email 14 | # read_emails_for 15 | # find_email 16 | # 17 | # General form for email scenarios are: 18 | # - clear the email queue (done automatically by email_spec) 19 | # - execute steps that sends an email 20 | # - check the user received an/no/[0-9] emails 21 | # - open the email 22 | # - inspect the email contents 23 | # - interact with the email (e.g. click links) 24 | # 25 | # The Cucumber steps below are setup in this order. 26 | 27 | module EmailHelpers 28 | def current_email_address 29 | # Replace with your a way to find your current email. e.g @current_user.email 30 | # last_email_address will return the last email address used by email spec to find an email. 31 | # Note that last_email_address will be reset after each Scenario. 32 | last_email_address || "example@example.com" 33 | end 34 | end 35 | 36 | World(EmailHelpers) 37 | 38 | # 39 | # Reset the e-mail queue within a scenario. 40 | # This is done automatically before each scenario. 41 | # 42 | 43 | Given /^(?:a clear email queue|no emails have been sent)$/ do 44 | reset_mailer 45 | end 46 | 47 | # 48 | # Check how many emails have been sent/received 49 | # 50 | 51 | Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails?$/ do |address, amount| 52 | unread_emails_for(address).size.should == parse_email_count(amount) 53 | end 54 | 55 | Then /^(?:I|they|"([^"]*?)") should have (an|no|\d+) emails?$/ do |address, amount| 56 | mailbox_for(address).size.should == parse_email_count(amount) 57 | end 58 | 59 | Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject "([^"]*?)"$/ do |address, amount, subject| 60 | unread_emails_for(address).select { |m| m.subject =~ Regexp.new(Regexp.escape(subject)) }.size.should == parse_email_count(amount) 61 | end 62 | 63 | Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject \/([^"]*?)\/$/ do |address, amount, subject| 64 | unread_emails_for(address).select { |m| m.subject =~ Regexp.new(subject) }.size.should == parse_email_count(amount) 65 | end 66 | 67 | Then /^(?:I|they|"([^"]*?)") should receive an email with the following body:$/ do |address, expected_body| 68 | open_email(address, :with_text => expected_body) 69 | end 70 | 71 | # 72 | # Accessing emails 73 | # 74 | 75 | # Opens the most recently received email 76 | When /^(?:I|they|"([^"]*?)") opens? the email$/ do |address| 77 | open_email(address) 78 | end 79 | 80 | When /^(?:I|they|"([^"]*?)") opens? the email with subject "([^"]*?)"$/ do |address, subject| 81 | open_email(address, :with_subject => subject) 82 | end 83 | 84 | When /^(?:I|they|"([^"]*?)") opens? the email with subject \/([^"]*?)\/$/ do |address, subject| 85 | open_email(address, :with_subject => Regexp.new(subject)) 86 | end 87 | 88 | When /^(?:I|they|"([^"]*?)") opens? the email with text "([^"]*?)"$/ do |address, text| 89 | open_email(address, :with_text => text) 90 | end 91 | 92 | When /^(?:I|they|"([^"]*?)") opens? the email with text \/([^"]*?)\/$/ do |address, text| 93 | open_email(address, :with_text => Regexp.new(text)) 94 | end 95 | 96 | # 97 | # Inspect the Email Contents 98 | # 99 | 100 | Then /^(?:I|they) should see "([^"]*?)" in the email subject$/ do |text| 101 | current_email.should have_subject(text) 102 | end 103 | 104 | Then /^(?:I|they) should see \/([^"]*?)\/ in the email subject$/ do |text| 105 | current_email.should have_subject(Regexp.new(text)) 106 | end 107 | 108 | Then /^(?:I|they) should see "([^"]*?)" in the email body$/ do |text| 109 | current_email.default_part_body.to_s.should include(text) 110 | end 111 | 112 | Then /^(?:I|they) should see \/([^"]*?)\/ in the email body$/ do |text| 113 | current_email.default_part_body.to_s.should =~ Regexp.new(text) 114 | end 115 | 116 | Then /^(?:I|they) should see the email delivered from "([^"]*?)"$/ do |text| 117 | current_email.should be_delivered_from(text) 118 | end 119 | 120 | Then /^(?:I|they) should see "([^\"]*)" in the email "([^"]*?)" header$/ do |text, name| 121 | current_email.should have_header(name, text) 122 | end 123 | 124 | Then /^(?:I|they) should see \/([^\"]*)\/ in the email "([^"]*?)" header$/ do |text, name| 125 | current_email.should have_header(name, Regexp.new(text)) 126 | end 127 | 128 | Then /^I should see it is a multi\-part email$/ do 129 | current_email.should be_multipart 130 | end 131 | 132 | Then /^(?:I|they) should see "([^"]*?)" in the email html part body$/ do |text| 133 | current_email.html_part.body.to_s.should include(text) 134 | end 135 | 136 | Then /^(?:I|they) should see "([^"]*?)" in the email text part body$/ do |text| 137 | current_email.text_part.body.to_s.should include(text) 138 | end 139 | 140 | # 141 | # Inspect the Email Attachments 142 | # 143 | 144 | Then /^(?:I|they) should see (an|no|\d+) attachments? with the email$/ do |amount| 145 | current_email_attachments.size.should == parse_email_count(amount) 146 | end 147 | 148 | Then /^there should be (an|no|\d+) attachments? named "([^"]*?)"$/ do |amount, filename| 149 | current_email_attachments.select { |a| a.filename == filename }.size.should == parse_email_count(amount) 150 | end 151 | 152 | Then /^attachment (\d+) should be named "([^"]*?)"$/ do |index, filename| 153 | current_email_attachments[(index.to_i - 1)].filename.should == filename 154 | end 155 | 156 | Then /^there should be (an|no|\d+) attachments? of type "([^"]*?)"$/ do |amount, content_type| 157 | current_email_attachments.select { |a| a.content_type.include?(content_type) }.size.should == parse_email_count(amount) 158 | end 159 | 160 | Then /^attachment (\d+) should be of type "([^"]*?)"$/ do |index, content_type| 161 | current_email_attachments[(index.to_i - 1)].content_type.should include(content_type) 162 | end 163 | 164 | Then /^all attachments should not be blank$/ do 165 | current_email_attachments.each do |attachment| 166 | attachment.read.size.should_not == 0 167 | end 168 | end 169 | 170 | Then /^show me a list of email attachments$/ do 171 | EmailSpec::EmailViewer::save_and_open_email_attachments_list(current_email) 172 | end 173 | 174 | # 175 | # Interact with Email Contents 176 | # 177 | 178 | When /^(?:I|they) follow "([^"]*?)" in the email$/ do |link| 179 | visit_in_email(link) 180 | end 181 | 182 | When /^(?:I|they) click the first link in the email$/ do 183 | click_first_link_in_email 184 | end 185 | 186 | # 187 | # Debugging 188 | # These only work with Rails and OSx ATM since EmailViewer uses RAILS_ROOT and OSx's 'open' command. 189 | # Patches accepted. ;) 190 | # 191 | 192 | Then /^save and open current email$/ do 193 | EmailSpec::EmailViewer::save_and_open_email(current_email) 194 | end 195 | 196 | Then /^save and open all text emails$/ do 197 | EmailSpec::EmailViewer::save_and_open_all_text_emails 198 | end 199 | 200 | Then /^save and open all html emails$/ do 201 | EmailSpec::EmailViewer::save_and_open_all_html_emails 202 | end 203 | 204 | Then /^save and open all raw emails$/ do 205 | EmailSpec::EmailViewer::save_and_open_all_raw_emails 206 | end 207 | -------------------------------------------------------------------------------- /features/step_definitions/user_steps.rb: -------------------------------------------------------------------------------- 1 | ### UTILITY METHODS ### 2 | 3 | def create_visitor 4 | @visitor ||= { :name => "Testy McUserton", :email => "example@example.com", 5 | :password => "changeme", :password_confirmation => "changeme" } 6 | end 7 | 8 | def find_user 9 | @user ||= User.first conditions: {:email => @visitor[:email]} 10 | end 11 | 12 | def create_unconfirmed_user 13 | create_visitor 14 | delete_user 15 | sign_up 16 | visit '/users/sign_out' 17 | end 18 | 19 | def create_user 20 | create_visitor 21 | delete_user 22 | @user = FactoryGirl.create(:user, email: @visitor[:email]) 23 | end 24 | 25 | def delete_user 26 | @user ||= User.first conditions: {:email => @visitor[:email]} 27 | @user.destroy unless @user.nil? 28 | end 29 | 30 | def sign_up 31 | delete_user 32 | visit '/users/sign_up' 33 | fill_in "Email", :with => @visitor[:email] 34 | click_button "Request Invitation" 35 | find_user 36 | end 37 | 38 | def sign_in 39 | visit '/users/sign_in' 40 | fill_in "Email", :with => @visitor[:email] 41 | fill_in "Password", :with => @visitor[:password] 42 | click_button "Sign in" 43 | end 44 | 45 | ### GIVEN ### 46 | Given /^I am not logged in$/ do 47 | visit '/users/sign_out' 48 | end 49 | 50 | Given /^I am logged in$/ do 51 | create_user 52 | sign_in 53 | end 54 | 55 | Given /^I exist as a user$/ do 56 | create_user 57 | end 58 | 59 | Given /^I do not exist as a user$/ do 60 | create_visitor 61 | delete_user 62 | end 63 | 64 | Given /^I exist as an unconfirmed user$/ do 65 | create_unconfirmed_user 66 | end 67 | 68 | ### WHEN ### 69 | When /^I sign in with valid credentials$/ do 70 | create_visitor 71 | sign_in 72 | end 73 | 74 | When /^I sign out$/ do 75 | visit '/users/sign_out' 76 | end 77 | 78 | When /^I sign up with valid user data$/ do 79 | create_visitor 80 | sign_up 81 | end 82 | 83 | When /^I sign up with an invalid email$/ do 84 | create_visitor 85 | @visitor = @visitor.merge(:email => "notanemail") 86 | sign_up 87 | end 88 | 89 | When /^I sign up without a password confirmation$/ do 90 | create_visitor 91 | @visitor = @visitor.merge(:password_confirmation => "") 92 | sign_up 93 | end 94 | 95 | When /^I sign up without a password$/ do 96 | create_visitor 97 | @visitor = @visitor.merge(:password => "") 98 | sign_up 99 | end 100 | 101 | When /^I sign up with a mismatched password confirmation$/ do 102 | create_visitor 103 | @visitor = @visitor.merge(:password_confirmation => "please123") 104 | sign_up 105 | end 106 | 107 | When /^I return to the site$/ do 108 | visit '/' 109 | end 110 | 111 | When /^I sign in with a wrong email$/ do 112 | @visitor = @visitor.merge(:email => "wrong@example.com") 113 | sign_in 114 | end 115 | 116 | When /^I sign in with a wrong password$/ do 117 | @visitor = @visitor.merge(:password => "wrongpass") 118 | sign_in 119 | end 120 | 121 | When /^I edit my account details$/ do 122 | click_link "Edit account" 123 | fill_in "Name", :with => "newname" 124 | fill_in "Current password", :with => @visitor[:password] 125 | click_button "Update" 126 | end 127 | 128 | When /^I look at the list of users$/ do 129 | visit '/' 130 | end 131 | 132 | ### THEN ### 133 | Then /^I should be signed in$/ do 134 | page.should have_content "Logout" 135 | page.should_not have_content "Sign up" 136 | page.should_not have_content "Login" 137 | end 138 | 139 | Then /^I should be signed out$/ do 140 | page.should have_content "Sign up" 141 | page.should have_content "Login" 142 | page.should_not have_content "Logout" 143 | end 144 | 145 | Then /^I see an unconfirmed account message$/ do 146 | page.should have_content "You have to confirm your account before continuing." 147 | end 148 | 149 | Then /^I see a successful sign in message$/ do 150 | page.should have_content "Signed in successfully." 151 | end 152 | 153 | Then /^I should see a successful sign up message$/ do 154 | page.should have_content "Thank You" 155 | end 156 | 157 | Then /^I should see an invalid email message$/ do 158 | page.should have_content "Email is invalid" 159 | end 160 | 161 | Then /^I should see a missing password message$/ do 162 | page.should have_content "Password can't be blank" 163 | end 164 | 165 | Then /^I should see a missing password confirmation message$/ do 166 | page.should have_content "Password doesn't match confirmation" 167 | end 168 | 169 | Then /^I should see a mismatched password message$/ do 170 | page.should have_content "Password doesn't match confirmation" 171 | end 172 | 173 | Then /^I should see a signed out message$/ do 174 | page.should have_content "Signed out successfully." 175 | end 176 | 177 | Then /^I see an invalid login message$/ do 178 | page.should have_content "Invalid email or password." 179 | end 180 | 181 | Then /^I should see an account edited message$/ do 182 | page.should have_content "You updated your account successfully." 183 | end 184 | 185 | Then /^I should see my name$/ do 186 | create_user 187 | page.should have_content @user[:name] 188 | end 189 | -------------------------------------------------------------------------------- /features/step_definitions/visitor_steps.rb: -------------------------------------------------------------------------------- 1 | def new_user 2 | @user ||= { :email => "example@example.com", 3 | :password => "please", :password_confirmation => "please" } 4 | end 5 | 6 | def invitation_request user 7 | visit '/users/sign_up' 8 | click_button "Request invite" 9 | fill_in "Email", :with => user[:email] 10 | click_button "Request Invitation" 11 | end 12 | 13 | When /^I visit the home page$/ do 14 | visit root_path 15 | end 16 | 17 | When /^I fill in "(.*?)" with "(.*?)"$/ do |field, value| 18 | fill_in field, with: value 19 | end 20 | 21 | When /^I click a button "([^"]*)"$/ do |arg1| 22 | click_button (arg1) 23 | end 24 | 25 | When /^I follow "(.*?)"$/ do |link| 26 | click_link(link) 27 | end 28 | 29 | Then /^I should see a form with a field "([^"]*)"$/ do |arg1| 30 | page.should have_content (arg1) 31 | end 32 | 33 | Then /^I should see a message "([^\"]*)"$/ do |arg1| 34 | page.should have_content (arg1) 35 | end 36 | 37 | Then /^my email address should be stored in the database$/ do 38 | test_user = User.find_by_email("example@example.com") 39 | test_user.should respond_to(:email) 40 | end 41 | 42 | Then /^my account should be unconfirmed$/ do 43 | test_user = User.find_by_email("example@example.com") 44 | test_user.confirmed_at.should be_nil 45 | end 46 | 47 | When /^I request an invitation with valid user data$/ do 48 | invitation_request new_user 49 | end 50 | 51 | When /^I request an invitation with an invalid email$/ do 52 | user = new_user.merge(:email => "notanemail") 53 | invitation_request user 54 | end 55 | -------------------------------------------------------------------------------- /features/support/email_spec.rb: -------------------------------------------------------------------------------- 1 | require 'email_spec/cucumber' 2 | -------------------------------------------------------------------------------- /features/support/env.rb: -------------------------------------------------------------------------------- 1 | # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. 2 | # It is recommended to regenerate this file in the future when you upgrade to a 3 | # newer version of cucumber-rails. Consider adding your own code to a new file 4 | # instead of editing this one. Cucumber will automatically load all features/**/*.rb 5 | # files. 6 | 7 | require 'cucumber/rails' 8 | 9 | # Capybara defaults to CSS3 selectors rather than XPath. 10 | # If you'd prefer to use XPath, just uncomment this line and adjust any 11 | # selectors in your step definitions to use the XPath syntax. 12 | # Capybara.default_selector = :xpath 13 | 14 | Capybara.javascript_driver = :webkit 15 | 16 | # By default, any exception happening in your Rails application will bubble up 17 | # to Cucumber so that your scenario will fail. This is a different from how 18 | # your application behaves in the production environment, where an error page will 19 | # be rendered instead. 20 | # 21 | # Sometimes we want to override this default behaviour and allow Rails to rescue 22 | # exceptions and display an error page (just like when the app is running in production). 23 | # Typical scenarios where you want to do this is when you test your error pages. 24 | # There are two ways to allow Rails to rescue exceptions: 25 | # 26 | # 1) Tag your scenario (or feature) with @allow-rescue 27 | # 28 | # 2) Set the value below to true. Beware that doing this globally is not 29 | # recommended as it will mask a lot of errors for you! 30 | # 31 | ActionController::Base.allow_rescue = false 32 | 33 | # Remove/comment out the lines below if your app doesn't have a database. 34 | # For some databases (like MongoDB and CouchDB) you may need to use :truncation instead. 35 | begin 36 | DatabaseCleaner.strategy = :transaction 37 | rescue NameError 38 | raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it." 39 | end 40 | 41 | # You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios. 42 | # See the DatabaseCleaner documentation for details. Example: 43 | # 44 | # Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do 45 | # # { :except => [:widgets] } may not do what you expect here 46 | # # as Cucumber::Rails::Database.javascript_strategy overrides 47 | # # this setting. 48 | # DatabaseCleaner.strategy = :truncation 49 | # end 50 | # 51 | # Before('~@no-txn', '~@selenium', '~@culerity', '~@celerity', '~@javascript') do 52 | # DatabaseCleaner.strategy = :transaction 53 | # end 54 | # 55 | 56 | # Possible values are :truncation and :transaction 57 | # The :transaction strategy is faster, but might give you threading problems. 58 | # See https://github.com/cucumber/cucumber-rails/blob/master/features/choose_javascript_database_strategy.feature 59 | Cucumber::Rails::Database.javascript_strategy = :truncation 60 | 61 | -------------------------------------------------------------------------------- /features/support/paths.rb: -------------------------------------------------------------------------------- 1 | module NavigationHelpers 2 | # Maps a name to a path. Used by the 3 | # 4 | # When /^I go to (.+)$/ do |page_name| 5 | # 6 | # step definition in web_steps.rb 7 | # 8 | def path_to(page_name) 9 | case page_name 10 | 11 | when /the home\s?page/ 12 | '/' 13 | 14 | when /the sign up page/ 15 | '/users/sign_up' 16 | 17 | when /the sign in page/ 18 | '/users/sign_in' 19 | 20 | # Add more mappings here. 21 | # Here is an example that pulls values out of the Regexp: 22 | # 23 | # when /^(.*)'s profile page$/i 24 | # user_profile_path(User.find_by_login($1)) 25 | 26 | else 27 | begin 28 | page_name =~ /the (.*) page/ 29 | path_components = $1.split(/\s+/) 30 | self.send(path_components.push('path').join('_').to_sym) 31 | rescue Object => e 32 | raise "Can't find mapping from \"#{page_name}\" to a path.\n" + 33 | "Now, go and add a mapping in #{__FILE__}" 34 | end 35 | end 36 | end 37 | end 38 | 39 | World(NavigationHelpers) 40 | -------------------------------------------------------------------------------- /features/users/sign_in.feature: -------------------------------------------------------------------------------- 1 | Feature: Sign in 2 | In order to get access to protected sections of the site 3 | A user 4 | Should be able to sign in 5 | 6 | Scenario: User is not signed up 7 | Given I do not exist as a user 8 | When I sign in with valid credentials 9 | Then I see an invalid login message 10 | And I should be signed out 11 | 12 | Scenario: User signs in successfully 13 | Given I exist as a user 14 | And I am not logged in 15 | When I sign in with valid credentials 16 | Then I see a successful sign in message 17 | When I return to the site 18 | Then I should be signed in 19 | 20 | Scenario: User enters wrong email 21 | Given I exist as a user 22 | And I am not logged in 23 | When I sign in with a wrong email 24 | Then I see an invalid login message 25 | And I should be signed out 26 | 27 | Scenario: User enters wrong password 28 | Given I exist as a user 29 | And I am not logged in 30 | When I sign in with a wrong password 31 | Then I see an invalid login message 32 | And I should be signed out 33 | -------------------------------------------------------------------------------- /features/users/sign_out.feature: -------------------------------------------------------------------------------- 1 | Feature: Sign out 2 | To protect my account from unauthorized access 3 | A signed in user 4 | Should be able to sign out 5 | 6 | Scenario: User signs out 7 | Given I am logged in 8 | When I sign out 9 | Then I should see a signed out message 10 | When I return to the site 11 | Then I should be signed out 12 | -------------------------------------------------------------------------------- /features/users/user_edit.feature: -------------------------------------------------------------------------------- 1 | Feature: Edit User 2 | As a registered user of the website 3 | I want to edit my user profile 4 | so I can change my username 5 | 6 | Scenario: I sign in and edit my account 7 | Given I am logged in 8 | When I edit my account details 9 | Then I should see an account edited message 10 | -------------------------------------------------------------------------------- /features/users/user_show.feature: -------------------------------------------------------------------------------- 1 | Feature: Show Users 2 | As a visitor to the website 3 | I want to see registered users listed on the homepage 4 | so I can know if the site has users 5 | 6 | -------------------------------------------------------------------------------- /features/visitors/request_invitation.feature: -------------------------------------------------------------------------------- 1 | @javascript 2 | Feature: Request Invitation 3 | As a visitor to the website 4 | I want to request an invitation 5 | so I can be notified when the site is launched 6 | 7 | Background: 8 | Given I am not logged in 9 | When I visit the home page 10 | And I follow "Request invite" 11 | 12 | Scenario: User signs up with valid data 13 | When I fill in "Email" with "example@example.com" 14 | And I click a button "Request Invitation" 15 | Then I should see a message "Thank you!" 16 | And my email address should be stored in the database 17 | And my account should be unconfirmed 18 | 19 | Scenario: User signs up with invalid email 20 | When I fill in "Email" with "NotAnEmail" 21 | And I click a button "Request Invitation" 22 | Then I should see an invalid email message 23 | -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RailsApps/rails-prelaunch-signup/3bebd16f324194a8432c31694e6d3edd34e697e8/lib/assets/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RailsApps/rails-prelaunch-signup/3bebd16f324194a8432c31694e6d3edd34e697e8/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/cucumber.rake: -------------------------------------------------------------------------------- 1 | # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. 2 | # It is recommended to regenerate this file in the future when you upgrade to a 3 | # newer version of cucumber-rails. Consider adding your own code to a new file 4 | # instead of editing this one. Cucumber will automatically load all features/**/*.rb 5 | # files. 6 | 7 | 8 | unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks 9 | 10 | vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first 11 | $LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? 12 | 13 | begin 14 | require 'cucumber/rake/task' 15 | 16 | namespace :cucumber do 17 | Cucumber::Rake::Task.new({:ok => 'test:prepare'}, 'Run features that should pass') do |t| 18 | t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. 19 | t.fork = true # You may get faster startup if you set this to false 20 | t.profile = 'default' 21 | end 22 | 23 | Cucumber::Rake::Task.new({:wip => 'test:prepare'}, 'Run features that are being worked on') do |t| 24 | t.binary = vendored_cucumber_bin 25 | t.fork = true # You may get faster startup if you set this to false 26 | t.profile = 'wip' 27 | end 28 | 29 | Cucumber::Rake::Task.new({:rerun => 'test:prepare'}, 'Record failing features and run only them if any exist') do |t| 30 | t.binary = vendored_cucumber_bin 31 | t.fork = true # You may get faster startup if you set this to false 32 | t.profile = 'rerun' 33 | end 34 | 35 | desc 'Run all features' 36 | task :all => [:ok, :wip] 37 | 38 | task :statsetup do 39 | require 'rails/code_statistics' 40 | ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features') 41 | ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features') 42 | end 43 | end 44 | desc 'Alias for cucumber:ok' 45 | task :cucumber => 'cucumber:ok' 46 | 47 | task :default => :cucumber 48 | 49 | task :features => :cucumber do 50 | STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" 51 | end 52 | 53 | # In case we don't have the generic Rails test:prepare hook, append a no-op task that we can depend upon. 54 | task 'test:prepare' do 55 | end 56 | 57 | task :stats => 'cucumber:statsetup' 58 | rescue LoadError 59 | desc 'cucumber rake task not available (cucumber not installed)' 60 | task :cucumber do 61 | abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' 62 | end 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /lib/templates/erb/scaffold/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%%= simple_form_for(@<%= singular_table_name %>) do |f| %> 2 | <%%= f.error_notification %> 3 | 4 |You may have mistyped the address or the page may have moved.
24 |Maybe you tried to change something you didn't have access to.
24 |