├── .eslintrc
├── .gitignore
├── .ruby-version
├── Gemfile
├── Gemfile.lock
├── Procfile
├── README.md
├── Rakefile
├── app
├── admin
│ ├── dashboard.rb
│ └── user.rb
├── assets
│ ├── javascripts
│ │ ├── application_common.js
│ │ ├── application_desktop.js
│ │ ├── application_phone.js
│ │ ├── common
│ │ │ ├── active_admin.js
│ │ │ ├── bootstrap.js
│ │ │ └── modal_behavior.js
│ │ ├── components.js
│ │ ├── components
│ │ │ ├── .gitkeep
│ │ │ ├── comments
│ │ │ │ └── CommentsNew.js.jsx
│ │ │ ├── pages
│ │ │ │ └── redux.js.jsx
│ │ │ └── posts
│ │ │ │ ├── PostsIndex.js.jsx
│ │ │ │ ├── PostsNew.js.jsx
│ │ │ │ └── PostsShow.js.jsx
│ │ ├── desktop
│ │ │ └── .gitkeep
│ │ ├── phone
│ │ │ └── .gitkeep
│ │ └── vendor
│ │ │ ├── fetch.js
│ │ │ ├── react-redux.min.js
│ │ │ └── redux.min.js
│ └── stylesheets
│ │ ├── application_common.scss
│ │ ├── application_desktop.scss
│ │ ├── application_phone.scss
│ │ ├── bootstrap
│ │ ├── custom.scss
│ │ └── devise_forms.scss
│ │ ├── common
│ │ ├── active_admin.scss
│ │ ├── alerts.scss
│ │ └── base.scss
│ │ ├── components
│ │ └── posts.scss
│ │ ├── desktop
│ │ └── .gitkeep
│ │ ├── environment
│ │ └── ribbon.scss
│ │ └── phone
│ │ └── .gitkeep
├── carriers
│ └── layout_carrier.rb
├── controllers
│ ├── api
│ │ └── v1
│ │ │ ├── base_controller.rb
│ │ │ ├── sessions_controller.rb
│ │ │ └── users_controller.rb
│ ├── application_controller.rb
│ ├── comments_controller.rb
│ ├── contacts_controller.rb
│ ├── home_controller.rb
│ ├── pages_controller.rb
│ ├── posts_controller.rb
│ ├── registrations_controller.rb
│ ├── sessions_controller.rb
│ └── superadmin
│ │ ├── base_controller.rb
│ │ └── users_controller.rb
├── helpers
│ └── application_helper.rb
├── mailers
│ └── mailer.rb
├── middleware
│ └── catch_json_parse_errors.rb
├── models
│ ├── comment.rb
│ ├── contact.rb
│ ├── post.rb
│ └── user.rb
├── services
│ └── addition_service.rb
├── uploaders
│ └── profile_image_uploader.rb
├── views
│ ├── home
│ │ └── index.html.haml
│ ├── layouts
│ │ ├── application.html+phone.haml
│ │ ├── application.html.haml
│ │ ├── mailer.haml
│ │ └── superadmin.html.haml
│ ├── mailer
│ │ └── contact_us_notification.html.haml
│ ├── pages
│ │ ├── about.html+phone.haml
│ │ ├── about.html.haml
│ │ ├── contact_us.html.haml
│ │ ├── index.html.haml
│ │ └── redux.html.haml
│ ├── posts
│ │ ├── _index.json.jbuilder
│ │ ├── _show.json.jbuilder
│ │ ├── index.html.haml
│ │ └── show.html.haml
│ ├── shared
│ │ ├── _bootstrap_flash.html.haml
│ │ ├── _modal.html.haml
│ │ ├── _nav.html.haml
│ │ ├── _superadmin_nav.html.haml
│ │ ├── _user_is_signed_in.html.haml
│ │ └── _user_right_nav.html.haml
│ ├── superadmin
│ │ └── users
│ │ │ ├── _edit_modal.html.haml
│ │ │ └── index.html.haml
│ └── users
│ │ ├── confirmations
│ │ └── new.html.haml
│ │ ├── mailer
│ │ ├── confirmation_instructions.html.haml
│ │ ├── reset_password_instructions.html.haml
│ │ └── unlock_instructions.html.haml
│ │ ├── passwords
│ │ ├── edit.html.haml
│ │ └── new.html.haml
│ │ ├── registrations
│ │ ├── edit.html.haml
│ │ ├── edit_password.html.haml
│ │ └── new.html.haml
│ │ ├── sessions
│ │ └── new.html.haml
│ │ ├── shared
│ │ └── _links.haml
│ │ └── unlocks
│ │ └── new.html.haml
└── workers
│ ├── base_worker.rb
│ └── event_notification_worker.rb
├── bin
├── bundle
├── delayed_job
├── honeybadger
├── rails
├── rake
├── setup
└── spring
├── circle.yml
├── config.ru
├── config
├── application.rb
├── boot.rb
├── database.yml.ci
├── database.yml.postgresql
├── database.yml.postgresqlapp
├── database.yml.sqlite3
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ ├── staging.rb
│ └── test.rb
├── honeybadger.yml
├── initializers
│ ├── active_admin.rb
│ ├── asset_precompile.rb
│ ├── assets.rb
│ ├── backtrace_silencers.rb
│ ├── carrierwave.rb
│ ├── catch_json_parser_errors.rb
│ ├── cookies_serializer.rb
│ ├── delayed_job_config.rb
│ ├── delayed_job_invoke_worker_automatically.rb
│ ├── devise.rb
│ ├── devise_async.rb
│ ├── email_interceptor.rb
│ ├── email_prefixer.rb
│ ├── filter_parameter_logging.rb
│ ├── honeybadger.rb
│ ├── inflections.rb
│ ├── marginalia.rb
│ ├── mime_types.rb
│ ├── rack_deflater.rb
│ ├── session_store.rb
│ ├── setup_email.rb
│ ├── simple_form.rb
│ ├── simple_form_bootstrap.rb
│ ├── tagged_logging.rb
│ └── wrap_parameters.rb
├── locales
│ ├── devise.en.yml
│ ├── en.bootstrap.yml
│ ├── en.yml
│ └── simple_form.en.yml
├── routes.rb
├── secrets.yml
└── unicorn.rb
├── db
├── migrate
│ ├── 20131112184628_add_devise_to_users.rb
│ ├── 20131120170220_create_delayed_jobs.rb
│ ├── 20131122045009_add_user_attributes.rb
│ ├── 20131213184726_create_active_admin_comments.rb
│ ├── 20140220111712_add_authentication_token_to_users.rb
│ ├── 20140225143027_add_profile_image_to_users.rb
│ ├── 20150827192424_create_posts.rb
│ └── 20150827192538_create_comments.rb
├── schema.rb
└── seeds.rb
├── doc
├── api.md
└── why_database_name_only_63_characters_long.md
├── lib
├── tasks
│ └── setup.rake
└── templates
│ └── erb
│ └── scaffold
│ └── _form.html.erb
├── public
├── 404.html
├── 422.html
├── 500.html
├── favicon.ico
└── robots.txt
└── test
├── controllers
├── active_admin
│ └── dashboard_controller_test.rb
├── api
│ └── v1
│ │ ├── sessions_controller_test.rb
│ │ └── users_controller_test.rb
├── contacts_controller_test.rb
├── home_controller_test.rb
├── pages_controller_test.rb
├── registrations_controller_test.rb
└── superadmin
│ └── users_controller_test.rb
├── fixtures
├── comments.yml
├── posts.yml
└── users.yml
├── integration
├── api_invalid_json_data_test.rb
└── compression_test.rb
├── models
├── comment_test.rb
├── contact_test.rb
├── post_test.rb
└── user_test.rb
├── services
└── addition_service_test.rb
└── test_helper.rb
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "env": {
4 | "browser": true,
5 | "es6": true,
6 | "node": true,
7 | "jquery": true // This will remove warnings related to $ being undefined. PR #97
8 | },
9 | "plugins": [
10 | "react" // This will remove warnings related to React not being defined. PR #98
11 | ],
12 | "ecmaFeatures": {
13 | "arrowFunctions": true,
14 | "blockBindings": true,
15 | "classes": true,
16 | "defaultParams": true,
17 | "destructuring": true,
18 | "forOf": true,
19 | "generators": true,
20 | "modules": true,
21 | "spread": true,
22 | "templateStrings": true,
23 | "jsx": true
24 | },
25 | "rules": {
26 | "consistent-return": [0],
27 | "key-spacing": [0],
28 | "quotes": [0],
29 | "new-cap": [0],
30 | "no-multi-spaces": [0],
31 | "no-shadow": [0],
32 |
33 | // allow alert
34 | "no-alert": [0],
35 |
36 | // in ReactJS it is common to have components defined first and then used later. PR #88
37 | "no-unused-vars": [0],
38 |
39 | //allow function names starting with underscore statements like this._executeQuery is being flagged. PR #86
40 | "no-underscore-dangle": [0],
41 |
42 | //In ReactNavite code it is common to have styles.xxx at the top while styles is defined later. PR #85
43 | "no-use-before-define": [0, "nofunc"],
44 |
45 | // Allow dangling commas
46 | "comma-dangle": [0],
47 |
48 | // Force space after keywords like if, else and before code blocks. PR #91
49 | "space-after-keywords": [2],
50 | "space-before-blocks": [2],
51 |
52 | // Don't warn if camelcase variable names are used. PR #96
53 | "camelcase": [0],
54 |
55 | // Prefer === over ==. PR #100
56 | "eqeqeq": [2]
57 |
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore the default SQLite database.
11 | /db/*.sqlite3
12 | /db/*.sqlite3-journal
13 |
14 | # Ignore database.yml file
15 | /config/database.yml
16 |
17 | # Ignore all logfiles and tempfiles.
18 | /log/*.log
19 | /tmp
20 | /db/backups
21 | public/uploads
22 | .idea
23 | *.DS_Store
24 | coverage
25 | .*swp
26 | /uploads/*
27 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.2.2
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | ruby '2.2.2'
4 |
5 | gem 'rails', '4.2.1'
6 |
7 | gem 'arel'
8 | gem 'jquery-rails'
9 |
10 | gem 'sprockets-rails', :require => 'sprockets/railtie'
11 | gem 'sass-rails', '>= 5.0.3'
12 | gem 'uglifier', '>= 2.7.1'
13 |
14 | # database
15 | gem 'sqlite3'
16 | # gem 'pg'
17 |
18 | # Sprockets support for .es6 files, using babel.
19 | gem 'sprockets-es6', require: 'sprockets/es6'
20 |
21 | # for building JSON
22 | gem 'jbuilder', '>= 2.2.13'
23 |
24 | # for authentication
25 | gem 'devise', '3.4.1'
26 |
27 | # for sending devise emails in background
28 | gem 'devise-async', git: 'https://github.com/mhfs/devise-async.git'
29 |
30 | # for background job processing
31 | gem 'delayed_job_active_record'
32 |
33 | # web interface for delayed job
34 | gem 'delayed_job_web', '>= 1.2.10'
35 |
36 | # For starting Delayed job background process
37 | gem 'daemons'
38 |
39 | # collection of handy tools
40 | gem 'handy'
41 |
42 | # for error tracking
43 | gem 'honeybadger'
44 |
45 | # use bootstrap3
46 | gem 'bootstrap-sass', '~> 3.3.3'
47 |
48 | # use font-awesome
49 | gem 'font-awesome-sass', '~> 4.3.0'
50 |
51 | # forms made easy for rails
52 | gem 'simple_form'
53 |
54 | # admin framework
55 | gem 'activeadmin', git: 'https://github.com/activeadmin/activeadmin'
56 |
57 | # for handling file uploads
58 | gem 'carrierwave'
59 |
60 | # for CarrierWave to upload files to cloud storage like Amazon S3
61 | gem 'fog', require: false
62 |
63 | # for CarrierWave to perform image manipulations
64 | #gem 'mini_magick'
65 |
66 | # for logging to work in heroku
67 | gem 'rails_12factor', group: [:staging, :production]
68 |
69 | # for email validation
70 | gem 'email_validator'
71 |
72 | # for variants support
73 | gem 'browser'
74 |
75 | # haml as templating engine
76 | gem 'haml-rails'
77 |
78 | # intercepts outgoing emails in non-production environment
79 | gem 'mail_interceptor', git: 'https://github.com/bigbinary/mail_interceptor', group: [:development, :staging]
80 |
81 | # Adds prefix to the subject in emails
82 | gem 'email_prefixer'
83 |
84 | # HTTP server for Rack applications for staging and production
85 | # See https://github.com/bigbinary/wheel/issues/43 for why unicorn is
86 | # not used in development.
87 | gem 'unicorn', group: [:staging, :production]
88 |
89 | group :development do
90 |
91 | # application server for development
92 | gem 'thin'
93 |
94 | # mutes assets pipeline log messages
95 | gem 'quiet_assets'
96 |
97 | # speeds up development by keeping your application running in the background
98 | gem 'spring'
99 |
100 | # web console
101 | gem 'web-console', '~> 2.0'
102 | end
103 |
104 | group :test do
105 |
106 | # customizable MiniTest output formats
107 | gem 'minitest-reporters', require: false
108 |
109 | # for test coverage report
110 | gem 'simplecov', require: false
111 |
112 | end
113 |
114 | # Attach comments to Active Record queries
115 | gem 'marginalia'
116 |
117 | gem 'react-rails', '1.6.0'
118 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GIT
2 | remote: https://github.com/activeadmin/activeadmin
3 | revision: 7ffcc55544d0624c6a242315798bbeff2b1e9078
4 | specs:
5 | activeadmin (1.0.0.pre2)
6 | arbre (~> 1.0, >= 1.0.2)
7 | bourbon
8 | coffee-rails
9 | formtastic (~> 3.1)
10 | formtastic_i18n
11 | inherited_resources (~> 1.6)
12 | jquery-rails
13 | jquery-ui-rails
14 | kaminari (~> 0.15)
15 | rails (>= 3.2, < 5.0)
16 | ransack (~> 1.3)
17 | sass-rails
18 |
19 | GIT
20 | remote: https://github.com/bigbinary/mail_interceptor
21 | revision: 8152faaf2481a4c0901fb32484a4393f37be83cd
22 | specs:
23 | mail_interceptor (0.0.6)
24 | activesupport
25 |
26 | GIT
27 | remote: https://github.com/mhfs/devise-async.git
28 | revision: 5c5971c625f7ebfcfccdc0d643fc60fa3bb28eb1
29 | specs:
30 | devise-async (0.10.1)
31 | devise (~> 3.2)
32 |
33 | GEM
34 | remote: https://rubygems.org/
35 | specs:
36 | CFPropertyList (2.3.1)
37 | actionmailer (4.2.1)
38 | actionpack (= 4.2.1)
39 | actionview (= 4.2.1)
40 | activejob (= 4.2.1)
41 | mail (~> 2.5, >= 2.5.4)
42 | rails-dom-testing (~> 1.0, >= 1.0.5)
43 | actionpack (4.2.1)
44 | actionview (= 4.2.1)
45 | activesupport (= 4.2.1)
46 | rack (~> 1.6)
47 | rack-test (~> 0.6.2)
48 | rails-dom-testing (~> 1.0, >= 1.0.5)
49 | rails-html-sanitizer (~> 1.0, >= 1.0.1)
50 | actionview (4.2.1)
51 | activesupport (= 4.2.1)
52 | builder (~> 3.1)
53 | erubis (~> 2.7.0)
54 | rails-dom-testing (~> 1.0, >= 1.0.5)
55 | rails-html-sanitizer (~> 1.0, >= 1.0.1)
56 | activejob (4.2.1)
57 | activesupport (= 4.2.1)
58 | globalid (>= 0.3.0)
59 | activemodel (4.2.1)
60 | activesupport (= 4.2.1)
61 | builder (~> 3.1)
62 | activerecord (4.2.1)
63 | activemodel (= 4.2.1)
64 | activesupport (= 4.2.1)
65 | arel (~> 6.0)
66 | activesupport (4.2.1)
67 | i18n (~> 0.7)
68 | json (~> 1.7, >= 1.7.7)
69 | minitest (~> 5.1)
70 | thread_safe (~> 0.3, >= 0.3.4)
71 | tzinfo (~> 1.1)
72 | ansi (1.5.0)
73 | arbre (1.0.3)
74 | activesupport (>= 3.0.0)
75 | arel (6.0.3)
76 | autoprefixer-rails (5.1.7)
77 | execjs
78 | json
79 | babel-source (5.8.35)
80 | babel-transpiler (0.7.0)
81 | babel-source (>= 4.0, < 6)
82 | execjs (~> 2.0)
83 | bcrypt (3.1.10)
84 | binding_of_caller (0.7.2)
85 | debug_inspector (>= 0.0.1)
86 | bootstrap-sass (3.3.3)
87 | autoprefixer-rails (>= 5.0.0.1)
88 | sass (>= 3.2.19)
89 | bourbon (4.2.6)
90 | sass (~> 3.4)
91 | thor (~> 0.19)
92 | browser (0.8.0)
93 | builder (3.2.2)
94 | carrierwave (0.10.0)
95 | activemodel (>= 3.2.0)
96 | activesupport (>= 3.2.0)
97 | json (>= 1.7)
98 | mime-types (>= 1.16)
99 | coffee-rails (4.1.1)
100 | coffee-script (>= 2.2.0)
101 | railties (>= 4.0.0, < 5.1.x)
102 | coffee-script (2.4.1)
103 | coffee-script-source
104 | execjs
105 | coffee-script-source (1.10.0)
106 | concurrent-ruby (1.0.0)
107 | connection_pool (2.2.0)
108 | daemons (1.1.9)
109 | debug_inspector (0.0.2)
110 | delayed_job (4.0.6)
111 | activesupport (>= 3.0, < 5.0)
112 | delayed_job_active_record (4.0.3)
113 | activerecord (>= 3.0, < 5.0)
114 | delayed_job (>= 3.0, < 4.1)
115 | delayed_job_web (1.2.10)
116 | activerecord (> 3.0.0)
117 | delayed_job (> 2.0.3)
118 | sinatra (>= 1.4.4)
119 | devise (3.4.1)
120 | bcrypt (~> 3.0)
121 | orm_adapter (~> 0.1)
122 | railties (>= 3.2.6, < 5)
123 | responders
124 | thread_safe (~> 0.1)
125 | warden (~> 1.2.3)
126 | docile (1.1.5)
127 | email_prefixer (1.1.0)
128 | rails (>= 4.0)
129 | email_validator (1.5.0)
130 | activemodel
131 | erubis (2.7.0)
132 | eventmachine (1.0.7)
133 | excon (0.45.4)
134 | execjs (2.6.0)
135 | fission (0.5.0)
136 | CFPropertyList (~> 2.2)
137 | fog (1.32.0)
138 | fog-atmos
139 | fog-aws (>= 0.6.0)
140 | fog-brightbox (~> 0.4)
141 | fog-core (~> 1.32)
142 | fog-ecloud (= 0.1.1)
143 | fog-google (>= 0.0.2)
144 | fog-json
145 | fog-local
146 | fog-powerdns (>= 0.1.1)
147 | fog-profitbricks
148 | fog-radosgw (>= 0.0.2)
149 | fog-riakcs
150 | fog-sakuracloud (>= 0.0.4)
151 | fog-serverlove
152 | fog-softlayer
153 | fog-storm_on_demand
154 | fog-terremark
155 | fog-vmfusion
156 | fog-voxel
157 | fog-xml (~> 0.1.1)
158 | ipaddress (~> 0.5)
159 | nokogiri (~> 1.5, >= 1.5.11)
160 | fog-atmos (0.1.0)
161 | fog-core
162 | fog-xml
163 | fog-aws (0.7.4)
164 | fog-core (~> 1.27)
165 | fog-json (~> 1.0)
166 | fog-xml (~> 0.1)
167 | ipaddress (~> 0.8)
168 | fog-brightbox (0.8.0)
169 | fog-core (~> 1.22)
170 | fog-json
171 | inflecto (~> 0.0.2)
172 | fog-core (1.32.0)
173 | builder
174 | excon (~> 0.45)
175 | formatador (~> 0.2)
176 | mime-types
177 | net-scp (~> 1.1)
178 | net-ssh (>= 2.1.3)
179 | fog-ecloud (0.1.1)
180 | fog-core
181 | fog-xml
182 | fog-google (0.0.7)
183 | fog-core
184 | fog-json
185 | fog-xml
186 | fog-json (1.0.2)
187 | fog-core (~> 1.0)
188 | multi_json (~> 1.10)
189 | fog-local (0.2.1)
190 | fog-core (~> 1.27)
191 | fog-powerdns (0.1.1)
192 | fog-core (~> 1.27)
193 | fog-json (~> 1.0)
194 | fog-xml (~> 0.1)
195 | fog-profitbricks (0.0.5)
196 | fog-core
197 | fog-xml
198 | nokogiri
199 | fog-radosgw (0.0.4)
200 | fog-core (>= 1.21.0)
201 | fog-json
202 | fog-xml (>= 0.0.1)
203 | fog-riakcs (0.1.0)
204 | fog-core
205 | fog-json
206 | fog-xml
207 | fog-sakuracloud (1.0.1)
208 | fog-core
209 | fog-json
210 | fog-serverlove (0.1.2)
211 | fog-core
212 | fog-json
213 | fog-softlayer (0.4.7)
214 | fog-core
215 | fog-json
216 | fog-storm_on_demand (0.1.1)
217 | fog-core
218 | fog-json
219 | fog-terremark (0.1.0)
220 | fog-core
221 | fog-xml
222 | fog-vmfusion (0.1.0)
223 | fission
224 | fog-core
225 | fog-voxel (0.1.0)
226 | fog-core
227 | fog-xml
228 | fog-xml (0.1.2)
229 | fog-core
230 | nokogiri (~> 1.5, >= 1.5.11)
231 | font-awesome-sass (4.3.1)
232 | sass (~> 3.2)
233 | formatador (0.2.5)
234 | formtastic (3.1.3)
235 | actionpack (>= 3.2.13)
236 | formtastic_i18n (0.5.0)
237 | globalid (0.3.6)
238 | activesupport (>= 4.1.0)
239 | haml (4.0.6)
240 | tilt
241 | haml-rails (0.8.2)
242 | actionpack (>= 4.0.1)
243 | activesupport (>= 4.0.1)
244 | haml (>= 3.1, < 5.0)
245 | html2haml (>= 1.0.1)
246 | railties (>= 4.0.1)
247 | handy (0.0.28)
248 | hashr
249 | has_scope (0.6.0)
250 | actionpack (>= 3.2, < 5)
251 | activesupport (>= 3.2, < 5)
252 | hashr (0.0.22)
253 | honeybadger (2.0.11)
254 | html2haml (2.0.0)
255 | erubis (~> 2.7.0)
256 | haml (~> 4.0.0)
257 | nokogiri (~> 1.6.0)
258 | ruby_parser (~> 3.5)
259 | i18n (0.7.0)
260 | inflecto (0.0.2)
261 | inherited_resources (1.6.0)
262 | actionpack (>= 3.2, < 5)
263 | has_scope (~> 0.6.0.rc)
264 | railties (>= 3.2, < 5)
265 | responders
266 | ipaddress (0.8.0)
267 | jbuilder (2.2.13)
268 | activesupport (>= 3.0.0, < 5)
269 | multi_json (~> 1.2)
270 | jquery-rails (4.0.3)
271 | rails-dom-testing (~> 1.0)
272 | railties (>= 4.2.0)
273 | thor (>= 0.14, < 2.0)
274 | jquery-ui-rails (5.0.5)
275 | railties (>= 3.2.16)
276 | json (1.8.3)
277 | kaminari (0.16.3)
278 | actionpack (>= 3.0.0)
279 | activesupport (>= 3.0.0)
280 | kgio (2.9.3)
281 | loofah (2.0.3)
282 | nokogiri (>= 1.5.9)
283 | mail (2.6.3)
284 | mime-types (>= 1.16, < 3)
285 | marginalia (1.3.0)
286 | actionpack (>= 2.3)
287 | activerecord (>= 2.3)
288 | mime-types (2.99)
289 | mini_portile2 (2.0.0)
290 | minitest (5.8.4)
291 | minitest-reporters (1.0.11)
292 | ansi
293 | builder
294 | minitest (>= 5.0)
295 | ruby-progressbar
296 | multi_json (1.11.1)
297 | net-scp (1.2.1)
298 | net-ssh (>= 2.6.5)
299 | net-ssh (2.9.2)
300 | nokogiri (1.6.7.2)
301 | mini_portile2 (~> 2.0.0.rc2)
302 | orm_adapter (0.5.0)
303 | polyamorous (1.3.0)
304 | activerecord (>= 3.0)
305 | quiet_assets (1.1.0)
306 | railties (>= 3.1, < 5.0)
307 | rack (1.6.4)
308 | rack-protection (1.5.3)
309 | rack
310 | rack-test (0.6.3)
311 | rack (>= 1.0)
312 | rails (4.2.1)
313 | actionmailer (= 4.2.1)
314 | actionpack (= 4.2.1)
315 | actionview (= 4.2.1)
316 | activejob (= 4.2.1)
317 | activemodel (= 4.2.1)
318 | activerecord (= 4.2.1)
319 | activesupport (= 4.2.1)
320 | bundler (>= 1.3.0, < 2.0)
321 | railties (= 4.2.1)
322 | sprockets-rails
323 | rails-deprecated_sanitizer (1.0.3)
324 | activesupport (>= 4.2.0.alpha)
325 | rails-dom-testing (1.0.7)
326 | activesupport (>= 4.2.0.beta, < 5.0)
327 | nokogiri (~> 1.6.0)
328 | rails-deprecated_sanitizer (>= 1.0.1)
329 | rails-html-sanitizer (1.0.3)
330 | loofah (~> 2.0)
331 | rails_12factor (0.0.3)
332 | rails_serve_static_assets
333 | rails_stdout_logging
334 | rails_serve_static_assets (0.0.4)
335 | rails_stdout_logging (0.0.3)
336 | railties (4.2.1)
337 | actionpack (= 4.2.1)
338 | activesupport (= 4.2.1)
339 | rake (>= 0.8.7)
340 | thor (>= 0.18.1, < 2.0)
341 | raindrops (0.13.0)
342 | rake (10.5.0)
343 | ransack (1.7.0)
344 | actionpack (>= 3.0)
345 | activerecord (>= 3.0)
346 | activesupport (>= 3.0)
347 | i18n
348 | polyamorous (~> 1.2)
349 | react-rails (1.6.0)
350 | babel-transpiler (>= 0.7.0)
351 | coffee-script-source (~> 1.8)
352 | connection_pool
353 | execjs
354 | rails (>= 3.2)
355 | tilt
356 | responders (2.1.0)
357 | railties (>= 4.2.0, < 5)
358 | ruby-progressbar (1.7.1)
359 | ruby_parser (3.6.4)
360 | sexp_processor (~> 4.1)
361 | sass (3.4.13)
362 | sass-rails (5.0.3)
363 | railties (>= 4.0.0, < 5.0)
364 | sass (~> 3.1)
365 | sprockets (>= 2.8, < 4.0)
366 | sprockets-rails (>= 2.0, < 4.0)
367 | tilt (~> 1.1)
368 | sexp_processor (4.4.5)
369 | simple_form (3.1.0)
370 | actionpack (~> 4.0)
371 | activemodel (~> 4.0)
372 | simplecov (0.9.2)
373 | docile (~> 1.1.0)
374 | multi_json (~> 1.0)
375 | simplecov-html (~> 0.9.0)
376 | simplecov-html (0.9.0)
377 | sinatra (1.4.5)
378 | rack (~> 1.4)
379 | rack-protection (~> 1.4)
380 | tilt (~> 1.3, >= 1.3.4)
381 | spring (1.3.3)
382 | sprockets (3.5.2)
383 | concurrent-ruby (~> 1.0)
384 | rack (> 1, < 3)
385 | sprockets-es6 (0.6.2)
386 | babel-transpiler
387 | sprockets (>= 3.0.0)
388 | sprockets-rails (3.0.0)
389 | actionpack (>= 4.0)
390 | activesupport (>= 4.0)
391 | sprockets (>= 3.0.0)
392 | sqlite3 (1.3.11)
393 | thin (1.6.3)
394 | daemons (~> 1.0, >= 1.0.9)
395 | eventmachine (~> 1.0)
396 | rack (~> 1.0)
397 | thor (0.19.1)
398 | thread_safe (0.3.5)
399 | tilt (1.4.1)
400 | tzinfo (1.2.2)
401 | thread_safe (~> 0.1)
402 | uglifier (2.7.1)
403 | execjs (>= 0.3.0)
404 | json (>= 1.8.0)
405 | unicorn (4.8.3)
406 | kgio (~> 2.6)
407 | rack
408 | raindrops (~> 0.7)
409 | warden (1.2.3)
410 | rack (>= 1.0)
411 | web-console (2.1.1)
412 | activemodel (>= 4.0)
413 | binding_of_caller (>= 0.7.2)
414 | railties (>= 4.0)
415 | sprockets-rails (>= 2.0, < 4.0)
416 |
417 | PLATFORMS
418 | ruby
419 |
420 | DEPENDENCIES
421 | activeadmin!
422 | arel
423 | bootstrap-sass (~> 3.3.3)
424 | browser
425 | carrierwave
426 | daemons
427 | delayed_job_active_record
428 | delayed_job_web (>= 1.2.10)
429 | devise (= 3.4.1)
430 | devise-async!
431 | email_prefixer
432 | email_validator
433 | fog
434 | font-awesome-sass (~> 4.3.0)
435 | haml-rails
436 | handy
437 | honeybadger
438 | jbuilder (>= 2.2.13)
439 | jquery-rails
440 | mail_interceptor!
441 | marginalia
442 | minitest-reporters
443 | quiet_assets
444 | rails (= 4.2.1)
445 | rails_12factor
446 | react-rails (= 1.6.0)
447 | sass-rails (>= 5.0.3)
448 | simple_form
449 | simplecov
450 | spring
451 | sprockets-es6
452 | sprockets-rails
453 | sqlite3
454 | thin
455 | uglifier (>= 2.7.1)
456 | unicorn
457 | web-console (~> 2.0)
458 |
459 | BUNDLED WITH
460 | 1.11.2
461 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
2 | worker: bundle exec rake jobs:work
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://circleci.com/gh/bigbinary/wheel)
2 |
3 | #### Setup
4 |
5 | ```
6 | bundle install
7 | cp config/database.yml.postgresqlapp config/database.yml
8 | rake setup
9 | bundle exec rails server
10 | ```
11 |
12 | #### Replace Wheel with your project name
13 |
14 | Let's say that the project name is `Pump`. Execute the command below to
15 | replace all occurrences of `Wheel` with `Pump`.
16 |
17 | ```
18 | perl -e "s/Wheel/Pump/g;" -pi $(find . -type f)
19 | ```
20 |
21 | #### Features
22 |
23 | - Uses [Bootstrap](http://getbootstrap.com) .
24 | - rake setup to set sensible sample data including user `sam@example.com` with password `welcome`.
25 | - Uses [devise](https://github.com/plataformatec/devise) .
26 | - Heroku ready. Push to heroku and it will work .
27 | - Uses [honeybadger](https://www.honeybadger.io).
28 | - Built in superadmin feature.
29 | - Uses modal box to showcase an example of editing information using modal box.
30 | - Enables __strict mode__ for all JavaScript code.
31 | - Uses __unicorn__ for staging and production.
32 | - Uses __thin__ for development and test.
33 | - An orange ribbon at the top for non-production environment.
34 | - Uses haml for cleaner syntax over erb.
35 | - No coffeescript. We prefer JavaScript.
36 | - No turbo-link.
37 | - Uses [ActiveAdmin](http://activeadmin.info).
38 | - When exception is sent to honeybadger then uuid is also sent for [debugging](http://videos.bigbinary.com/rubyonrails/use-uuid-x-request-id-to-debug-rails-application.html) .
39 | - Uses [DelayedJob](https://github.com/collectiveidea/delayed_job).
40 | - Intercepts all outgoing emails in non production environment using gem [mail_interceptor](https://github.com/bigbinary/mail_interceptor).
41 | - Uses [CircleCI](https://circleci.com) for continuous testing.
42 | - Has a bunch of tests to make it easier to get started with new tests.
43 | - Uses PostgreSQL.
44 | - Built in support for [carrierwave](https://github.com/carrierwaveuploader/carrierwave) to easily upload items to s3.
45 | - Built in support for "variants" so the pages can be customized for tablet or phone easily.
46 | - Uses [simple_form](https://github.com/plataformatec/simple_form).
47 | - Built in support for [mandrill](http://how-we-work.bigbinary.com/externalservices/mandrill.html).
48 | - Easy to generate "test coverage".
49 | - Content compression via [Rack::Deflater](https://github.com/rack/rack/blob/master/lib/rack/deflater.rb).
50 |
51 |
52 | #### Brought to you by
53 |
54 | [](http://BigBinary.com)
55 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require File.expand_path('../config/application', __FILE__)
5 |
6 | Wheel::Application.load_tasks
7 |
--------------------------------------------------------------------------------
/app/admin/dashboard.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin.register_page "Dashboard" do
2 |
3 | menu priority: 1, label: proc { I18n.t("active_admin.dashboard") }
4 |
5 | content :title => proc { I18n.t("active_admin.dashboard") } do
6 | div :class => "blank_slate_container", :id => "dashboard_default_message" do
7 | span :class => "blank_slate" do
8 | span I18n.t("active_admin.dashboard_welcome.welcome")
9 | small I18n.t("active_admin.dashboard_welcome.call_to_action")
10 | end
11 | end
12 |
13 | # Here is an example of a simple dashboard with columns and panels.
14 | #
15 | # columns do
16 | # column do
17 | # panel "Recent Posts" do
18 | # ul do
19 | # Post.recent(5).map do |post|
20 | # li link_to(post.title, admin_post_path(post))
21 | # end
22 | # end
23 | # end
24 | # end
25 |
26 | # column do
27 | # panel "Info" do
28 | # para "Welcome to ActiveAdmin."
29 | # end
30 | # end
31 | # end
32 | end # content
33 | end
34 |
--------------------------------------------------------------------------------
/app/admin/user.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin.register User do
2 |
3 | permit_params :email, :password, :password_confirmation
4 |
5 | index do
6 | column :email
7 | column :current_sign_in_at
8 | column :last_sign_in_at
9 | column :sign_in_count
10 | end
11 |
12 | filter :email
13 |
14 | form do |f|
15 | f.inputs "Admin Details" do
16 | f.input :email
17 | f.input :password
18 | f.input :password_confirmation
19 | end
20 | f.actions
21 | end
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/app/assets/javascripts/application_common.js:
--------------------------------------------------------------------------------
1 | //= require jquery
2 | //= require jquery_ujs
3 | //= require bootstrap-sprockets
4 | //= require react
5 | //= require react_ujs
6 | //= require_tree ./vendor
7 | //= require components
8 |
9 | //
10 | //= require_tree ./common
11 |
--------------------------------------------------------------------------------
/app/assets/javascripts/application_desktop.js:
--------------------------------------------------------------------------------
1 | //= require ./application_common
2 | //= require_tree ./desktop
3 |
--------------------------------------------------------------------------------
/app/assets/javascripts/application_phone.js:
--------------------------------------------------------------------------------
1 | //= require ./application_common
2 | //= require_tree ./phone
3 |
--------------------------------------------------------------------------------
/app/assets/javascripts/common/active_admin.js:
--------------------------------------------------------------------------------
1 | #= require active_admin/base
2 |
--------------------------------------------------------------------------------
/app/assets/javascripts/common/bootstrap.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | $("a[rel~=popover], .has-popover").popover();
4 |
5 | return $("a[rel~=tooltip], .has-tooltip").tooltip();
6 |
7 | });
8 |
--------------------------------------------------------------------------------
/app/assets/javascripts/common/modal_behavior.js:
--------------------------------------------------------------------------------
1 | if ( Modal !== undefined ) {
2 | alert('Modal is already defined');
3 | }
4 |
5 | var Modal = (function() {
6 |
7 | var modalContentSelector = "[data-behavior ~= modal-content]",
8 | modalContainerSelector = "[data-behavior ~= modal-container]";
9 |
10 | function _displayModal(link) {
11 | var $modalContainer = _findOrCreateModalContainer(),
12 | url = link.data('url');
13 |
14 | $modalContainer.load(url, function() {
15 | var $element = $(this).find(modalContentSelector);
16 | $element.show();
17 | $element.find('[data-focus~=true]').focus();
18 | });
19 | }
20 |
21 | function _findOrCreateModalContainer() {
22 | var element;
23 |
24 | if ($(modalContainerSelector).length) {
25 | element = $(modalContainerSelector);
26 | } else {
27 | element = $('
');
28 | $('body').append(element);
29 | }
30 |
31 | return element
32 | };
33 |
34 | function _formSubmissionResponseHandler(data) {
35 | var modalContainer = _findOrCreateModalContainer();
36 |
37 | if (data.modal_content) {
38 | modalContainer.html(data.modal_content)
39 | modalContainer.find(modalContentSelector).show();
40 |
41 | } else if (data.redirect_to) {
42 | window.location.href = data.redirect_to;
43 |
44 | } else {
45 | modalContainer.find(modalContentSelector).hide();
46 | };
47 | }
48 |
49 | function displayInModal(event) {
50 | event.preventDefault();
51 | _displayModal($(this));
52 | };
53 |
54 | function hide(event) {
55 | event.preventDefault()
56 | $(this).closest(modalContentSelector).hide();
57 | };
58 |
59 | function submitForm(event){
60 | var form = $(this);
61 | event.preventDefault();
62 |
63 | $.ajax({
64 | type: form.attr('method'),
65 | url: form.attr('action'),
66 | data: form.serialize()
67 | }).done(_formSubmissionResponseHandler);
68 | };
69 |
70 | return { "displayInModal": displayInModal,
71 | "hide": hide,
72 | "submitForm": submitForm }
73 |
74 | })();
75 |
76 | $(document).on('click', 'a[data-behavior ~= display-in-modal]', Modal.displayInModal);
77 | $(document).on("click", "[data-behavior ~= modal-close]", Modal.hide)
78 | $(document).on('submit', "[data-behavior ~= modal-container] form", Modal.submitForm)
79 |
--------------------------------------------------------------------------------
/app/assets/javascripts/components.js:
--------------------------------------------------------------------------------
1 | //= require_tree ./components
2 |
--------------------------------------------------------------------------------
/app/assets/javascripts/components/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vipulnsward/react-rails-examples/a8fdfc190d6ffbddfe11c9e9c7574345ad8ad9c8/app/assets/javascripts/components/.gitkeep
--------------------------------------------------------------------------------
/app/assets/javascripts/components/comments/CommentsNew.js.jsx:
--------------------------------------------------------------------------------
1 | class CommentsNew extends React.Component {
2 | constructor(props) {
3 | super(props);
4 | var {post} = this.props;
5 | post = JSON.parse(post);
6 |
7 | this.state = {user_id: this.props.user_id, post: post}
8 | }
9 |
10 | render() {
11 | var errorMessage = this.renderError();
12 | return (
13 |
14 | {errorMessage}
15 |
32 |
33 | );
34 | }
35 |
36 | renderError() {
37 | if (this.state.errors) {
38 | var errors = this.state.errors;
39 | return (
40 |
41 |
42 | {Object.keys(errors).map((error_key) => {
43 | return - {error_key} : {errors[error_key].join(', ')}
44 | })}
45 |
46 |
47 | );
48 | }
49 | }
50 |
51 | handleChange(event, attribute) {
52 | var newState = this.state;
53 | newState[attribute] = event.target.value;
54 | newState.errors = null;
55 | this.setState(newState);
56 | console.log(this.state);
57 | }
58 |
59 |
60 | setComments(comments_response) {
61 | if (comments_response.errors) {
62 | this.setState({errors: comments_response.errors})
63 | } else {
64 | this.props.setComments(comments_response.comments);
65 | }
66 | }
67 |
68 | parseJSON(response) {
69 | return response.json()
70 | }
71 |
72 | submitComment(event) {
73 | event.preventDefault();
74 |
75 | fetch(this.state.post.new_comment_url, {
76 | method: 'post',
77 | headers: {
78 | 'Accept': 'application/json',
79 | 'Content-Type': 'application/json'
80 | },
81 | body: JSON.stringify({comment: this.state})
82 | }).then(::this.parseJSON)
83 | .then(::this.setComments)
84 | .catch(function (ex) {
85 | console.log('parsing failed', ex)
86 | });
87 |
88 | this.setState({content: null});
89 |
90 | }
91 | }
92 |
93 |
94 |
--------------------------------------------------------------------------------
/app/assets/javascripts/components/pages/redux.js.jsx:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | let {createStore} = Redux;
4 | let { Provider, connect } = ReactRedux;
5 |
6 | // React component
7 | class Counter extends React.Component {
8 | render() {
9 | const { value, onIncreaseClick } = this.props;
10 | return (
11 |
12 | Counter Value is {value}
13 |
14 |
15 | );
16 | }
17 | }
18 |
19 | // Action:
20 | const increaseAction = {type: 'increase'};
21 |
22 | // Reducer:
23 | function counter(state = {count: 0}, action) {
24 | let count = state.count;
25 | switch (action.type) {
26 | case 'increase':
27 | return {count: count + 1};
28 | default:
29 | return state;
30 | }
31 | }
32 |
33 | // Store:
34 | let store = createStore(counter);
35 |
36 | // Map Redux state to component props
37 | function mapStateToProps(state) {
38 | return {
39 | value: state.count
40 | };
41 | }
42 |
43 | // Map Redux actions to component props
44 | function mapDispatchToProps(dispatch) {
45 | return {
46 | onIncreaseClick: () => dispatch(increaseAction)
47 | };
48 | }
49 |
50 | // Connected Component:
51 | let App = connect(
52 | mapStateToProps,
53 | mapDispatchToProps
54 | )(Counter);
55 |
56 |
57 | $(document).ready(function () {
58 | if (document.getElementById('redux-root')) {
59 | React.render(
60 |
61 | {() => }
62 | ,
63 | document.getElementById('redux-root')
64 | );
65 | }
66 | });
67 |
68 |
--------------------------------------------------------------------------------
/app/assets/javascripts/components/posts/PostsIndex.js.jsx:
--------------------------------------------------------------------------------
1 | let ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
2 |
3 | class PostsIndex extends React.Component {
4 | constructor(props){
5 | super(props);
6 | var {posts} = this.props;
7 | posts = JSON.parse(posts);
8 | console.log(posts);
9 | this.state = {posts: posts};
10 | }
11 |
12 | render() {
13 | let postsDisplay = this.state.posts.map((post) => {
14 | return this.renderPost(post)
15 | });
16 | return (
17 |
18 |
All Posts
19 |
20 |
21 | {postsDisplay}
22 |
23 |
24 |
25 | New Post:
26 |
27 |
28 | );
29 | }
30 |
31 | setPosts(posts){
32 | this.setState({posts: posts});
33 | }
34 |
35 | renderPost(post) {
36 | return (
37 | {post.title}: {post.content}
38 | )
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/app/assets/javascripts/components/posts/PostsNew.js.jsx:
--------------------------------------------------------------------------------
1 | class PostsNew extends React.Component {
2 | constructor(props) {
3 | super(props);
4 | this.state = {user_id: this.props.user_id}
5 | }
6 |
7 | render() {
8 | var errorMessage = this.renderError();
9 | return (
10 |
11 | {errorMessage}
12 |
37 |
38 | );
39 | }
40 |
41 | renderError() {
42 | if (this.state.errors) {
43 | var errors = this.state.errors;
44 | return (
45 |
46 |
47 | {Object.keys(errors).map((error_key) => {
48 | return - {error_key} : {errors[error_key].join(', ')}
49 | })}
50 |
51 |
52 | );
53 | }
54 | }
55 |
56 | handleChange(event, attribute) {
57 | var newState = this.state;
58 | newState[attribute] = event.target.value;
59 | newState.errors = null;
60 | this.setState(newState);
61 | console.log(this.state);
62 | }
63 |
64 |
65 | setPosts(posts) {
66 | if (posts.errors) {
67 | this.setState({errors: posts.errors})
68 | } else {
69 | this.props.setPosts(posts);
70 | }
71 | }
72 |
73 | parseJSON(response) {
74 | return response.json()
75 | }
76 |
77 | submitPost(event) {
78 | event.preventDefault();
79 |
80 | fetch('/posts', {
81 | method: 'post',
82 | headers: {
83 | 'Accept': 'application/json',
84 | 'Content-Type': 'application/json'
85 | },
86 | body: JSON.stringify({post: this.state})
87 | }).then(::this.parseJSON)
88 | .then(::this.setPosts)
89 | .catch(function (ex) {
90 | console.log('parsing failed', ex)
91 | });
92 |
93 | }
94 | }
95 |
96 |
97 |
--------------------------------------------------------------------------------
/app/assets/javascripts/components/posts/PostsShow.js.jsx:
--------------------------------------------------------------------------------
1 | class PostsShow extends React.Component {
2 | constructor(props){
3 | super(props);
4 | var {post} = props;
5 |
6 | post = JSON.parse(post);
7 | this.state = {post: post, comments: post.comments}
8 | }
9 |
10 | render() {
11 | let {post, comments} = this.state;
12 | let commentsDisplay = comments.map((comment) => {
13 | return this.renderComment(comment)
14 | });
15 |
16 |
17 | return (
18 |
19 |
{post.title}
20 |
21 | {post.content}
22 |
23 |
24 |
25 |
Comments:
26 |
27 |
28 |
29 | );
30 | }
31 |
32 | renderComment(comment) {
33 | return (
34 | {comment.user_name}- {comment.content}
35 | )
36 | }
37 |
38 | setComments(comments){
39 | this.setState({comments: comments});
40 | }
41 | }
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/assets/javascripts/desktop/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vipulnsward/react-rails-examples/a8fdfc190d6ffbddfe11c9e9c7574345ad8ad9c8/app/assets/javascripts/desktop/.gitkeep
--------------------------------------------------------------------------------
/app/assets/javascripts/phone/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vipulnsward/react-rails-examples/a8fdfc190d6ffbddfe11c9e9c7574345ad8ad9c8/app/assets/javascripts/phone/.gitkeep
--------------------------------------------------------------------------------
/app/assets/javascripts/vendor/fetch.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | if (self.fetch) {
5 | return
6 | }
7 |
8 | function normalizeName(name) {
9 | if (typeof name !== 'string') {
10 | name = String(name)
11 | }
12 | if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
13 | throw new TypeError('Invalid character in header field name')
14 | }
15 | return name.toLowerCase()
16 | }
17 |
18 | function normalizeValue(value) {
19 | if (typeof value !== 'string') {
20 | value = String(value)
21 | }
22 | return value
23 | }
24 |
25 | function Headers(headers) {
26 | this.map = {}
27 |
28 | if (headers instanceof Headers) {
29 | headers.forEach(function(value, name) {
30 | this.append(name, value)
31 | }, this)
32 |
33 | } else if (headers) {
34 | Object.getOwnPropertyNames(headers).forEach(function(name) {
35 | this.append(name, headers[name])
36 | }, this)
37 | }
38 | }
39 |
40 | Headers.prototype.append = function(name, value) {
41 | name = normalizeName(name)
42 | value = normalizeValue(value)
43 | var list = this.map[name]
44 | if (!list) {
45 | list = []
46 | this.map[name] = list
47 | }
48 | list.push(value)
49 | }
50 |
51 | Headers.prototype['delete'] = function(name) {
52 | delete this.map[normalizeName(name)]
53 | }
54 |
55 | Headers.prototype.get = function(name) {
56 | var values = this.map[normalizeName(name)]
57 | return values ? values[0] : null
58 | }
59 |
60 | Headers.prototype.getAll = function(name) {
61 | return this.map[normalizeName(name)] || []
62 | }
63 |
64 | Headers.prototype.has = function(name) {
65 | return this.map.hasOwnProperty(normalizeName(name))
66 | }
67 |
68 | Headers.prototype.set = function(name, value) {
69 | this.map[normalizeName(name)] = [normalizeValue(value)]
70 | }
71 |
72 | Headers.prototype.forEach = function(callback, thisArg) {
73 | Object.getOwnPropertyNames(this.map).forEach(function(name) {
74 | this.map[name].forEach(function(value) {
75 | callback.call(thisArg, value, name, this)
76 | }, this)
77 | }, this)
78 | }
79 |
80 | function consumed(body) {
81 | if (body.bodyUsed) {
82 | return Promise.reject(new TypeError('Already read'))
83 | }
84 | body.bodyUsed = true
85 | }
86 |
87 | function fileReaderReady(reader) {
88 | return new Promise(function(resolve, reject) {
89 | reader.onload = function() {
90 | resolve(reader.result)
91 | }
92 | reader.onerror = function() {
93 | reject(reader.error)
94 | }
95 | })
96 | }
97 |
98 | function readBlobAsArrayBuffer(blob) {
99 | var reader = new FileReader()
100 | reader.readAsArrayBuffer(blob)
101 | return fileReaderReady(reader)
102 | }
103 |
104 | function readBlobAsText(blob) {
105 | var reader = new FileReader()
106 | reader.readAsText(blob)
107 | return fileReaderReady(reader)
108 | }
109 |
110 | var support = {
111 | blob: 'FileReader' in self && 'Blob' in self && (function() {
112 | try {
113 | new Blob();
114 | return true
115 | } catch(e) {
116 | return false
117 | }
118 | })(),
119 | formData: 'FormData' in self
120 | }
121 |
122 | function Body() {
123 | this.bodyUsed = false
124 |
125 |
126 | this._initBody = function(body) {
127 | this._bodyInit = body
128 | if (typeof body === 'string') {
129 | this._bodyText = body
130 | } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
131 | this._bodyBlob = body
132 | } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
133 | this._bodyFormData = body
134 | } else if (!body) {
135 | this._bodyText = ''
136 | } else {
137 | throw new Error('unsupported BodyInit type')
138 | }
139 | }
140 |
141 | if (support.blob) {
142 | this.blob = function() {
143 | var rejected = consumed(this)
144 | if (rejected) {
145 | return rejected
146 | }
147 |
148 | if (this._bodyBlob) {
149 | return Promise.resolve(this._bodyBlob)
150 | } else if (this._bodyFormData) {
151 | throw new Error('could not read FormData body as blob')
152 | } else {
153 | return Promise.resolve(new Blob([this._bodyText]))
154 | }
155 | }
156 |
157 | this.arrayBuffer = function() {
158 | return this.blob().then(readBlobAsArrayBuffer)
159 | }
160 |
161 | this.text = function() {
162 | var rejected = consumed(this)
163 | if (rejected) {
164 | return rejected
165 | }
166 |
167 | if (this._bodyBlob) {
168 | return readBlobAsText(this._bodyBlob)
169 | } else if (this._bodyFormData) {
170 | throw new Error('could not read FormData body as text')
171 | } else {
172 | return Promise.resolve(this._bodyText)
173 | }
174 | }
175 | } else {
176 | this.text = function() {
177 | var rejected = consumed(this)
178 | return rejected ? rejected : Promise.resolve(this._bodyText)
179 | }
180 | }
181 |
182 | if (support.formData) {
183 | this.formData = function() {
184 | return this.text().then(decode)
185 | }
186 | }
187 |
188 | this.json = function() {
189 | return this.text().then(JSON.parse)
190 | }
191 |
192 | return this
193 | }
194 |
195 | // HTTP methods whose capitalization should be normalized
196 | var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']
197 |
198 | function normalizeMethod(method) {
199 | var upcased = method.toUpperCase()
200 | return (methods.indexOf(upcased) > -1) ? upcased : method
201 | }
202 |
203 | function Request(input, options) {
204 | options = options || {}
205 | var body = options.body
206 | if (Request.prototype.isPrototypeOf(input)) {
207 | if (input.bodyUsed) {
208 | throw new TypeError('Already read')
209 | }
210 | this.url = input.url
211 | this.credentials = input.credentials
212 | if (!options.headers) {
213 | this.headers = new Headers(input.headers)
214 | }
215 | this.method = input.method
216 | this.mode = input.mode
217 | if (!body) {
218 | body = input._bodyInit
219 | input.bodyUsed = true
220 | }
221 | } else {
222 | this.url = input
223 | }
224 |
225 | this.credentials = options.credentials || this.credentials || 'omit'
226 | if (options.headers || !this.headers) {
227 | this.headers = new Headers(options.headers)
228 | }
229 | this.method = normalizeMethod(options.method || this.method || 'GET')
230 | this.mode = options.mode || this.mode || null
231 | this.referrer = null
232 |
233 | if ((this.method === 'GET' || this.method === 'HEAD') && body) {
234 | throw new TypeError('Body not allowed for GET or HEAD requests')
235 | }
236 | this._initBody(body)
237 | }
238 |
239 | function decode(body) {
240 | var form = new FormData()
241 | body.trim().split('&').forEach(function(bytes) {
242 | if (bytes) {
243 | var split = bytes.split('=')
244 | var name = split.shift().replace(/\+/g, ' ')
245 | var value = split.join('=').replace(/\+/g, ' ')
246 | form.append(decodeURIComponent(name), decodeURIComponent(value))
247 | }
248 | })
249 | return form
250 | }
251 |
252 | function headers(xhr) {
253 | var head = new Headers()
254 | var pairs = xhr.getAllResponseHeaders().trim().split('\n')
255 | pairs.forEach(function(header) {
256 | var split = header.trim().split(':')
257 | var key = split.shift().trim()
258 | var value = split.join(':').trim()
259 | head.append(key, value)
260 | })
261 | return head
262 | }
263 |
264 | Body.call(Request.prototype)
265 |
266 | function Response(bodyInit, options) {
267 | if (!options) {
268 | options = {}
269 | }
270 |
271 | this._initBody(bodyInit)
272 | this.type = 'default'
273 | this.url = null
274 | this.status = options.status
275 | this.ok = this.status >= 200 && this.status < 300
276 | this.statusText = options.statusText
277 | this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers)
278 | this.url = options.url || ''
279 | }
280 |
281 | Body.call(Response.prototype)
282 |
283 | self.Headers = Headers;
284 | self.Request = Request;
285 | self.Response = Response;
286 |
287 | self.fetch = function(input, init) {
288 | var request
289 | if (Request.prototype.isPrototypeOf(input) && !init) {
290 | request = input
291 | } else {
292 | request = new Request(input, init)
293 | }
294 |
295 | return new Promise(function(resolve, reject) {
296 | var xhr = new XMLHttpRequest()
297 |
298 | function responseURL() {
299 | if ('responseURL' in xhr) {
300 | return xhr.responseURL
301 | }
302 |
303 | // Avoid security warnings on getResponseHeader when not allowed by CORS
304 | if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) {
305 | return xhr.getResponseHeader('X-Request-URL')
306 | }
307 |
308 | return;
309 | }
310 |
311 | xhr.onload = function() {
312 | var status = (xhr.status === 1223) ? 204 : xhr.status
313 | if (status < 100 || status > 599) {
314 | reject(new TypeError('Network request failed'))
315 | return
316 | }
317 | var options = {
318 | status: status,
319 | statusText: xhr.statusText,
320 | headers: headers(xhr),
321 | url: responseURL()
322 | }
323 | var body = 'response' in xhr ? xhr.response : xhr.responseText;
324 | resolve(new Response(body, options))
325 | }
326 |
327 | xhr.onerror = function() {
328 | reject(new TypeError('Network request failed'))
329 | }
330 |
331 | xhr.open(request.method, request.url, true)
332 |
333 | if (request.credentials === 'include') {
334 | xhr.withCredentials = true
335 | }
336 |
337 | if ('responseType' in xhr && support.blob) {
338 | xhr.responseType = 'blob'
339 | }
340 |
341 | request.headers.forEach(function(value, name) {
342 | xhr.setRequestHeader(name, value)
343 | })
344 |
345 | xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
346 | })
347 | }
348 | self.fetch.polyfill = true
349 | })();
350 |
--------------------------------------------------------------------------------
/app/assets/javascripts/vendor/react-redux.min.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react"),require("redux")):"function"==typeof define&&define.amd?define(["react","redux"],e):"object"==typeof exports?exports.ReactRedux=e(require("react"),require("redux")):t.ReactRedux=e(t.React,t.Redux)}(this,function(t,e){return function(t){function e(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return t[n].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}e.__esModule=!0;var o=r(10),u=n(o),i=r(2),s=n(i),a=s.default(u.default),c=a.Provider,p=a.connect;e.Provider=c,e.connect=p},function(t,e){"use strict";function r(t){return t.shape({subscribe:t.func.isRequired,dispatch:t.func.isRequired,getState:t.func.isRequired})}e.__esModule=!0,e.default=r,t.exports=e.default},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t){var e=i.default(t),r=a.default(t);return{Provider:e,connect:r}}e.__esModule=!0,e.default=o;var u=r(4),i=n(u),s=r(3),a=n(s);t.exports=e.default},function(t,e,r){(function(n){"use strict";function o(t){return t&&t.__esModule?t:{"default":t}}function u(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function s(t){return t.displayName||t.name||"Component"}function a(t){var e=t.Component,r=t.PropTypes,o=l.default(r);return function(r,a,f){function l(t,e){var r=t.getState(),n=R?g(r,e):g(r);return _.default(v.default(n),"`mapStateToProps` must return an object. Instead received %s.",n),n}function d(t,e){var r=t.dispatch,n=T?O(r,e):O(r);return _.default(v.default(n),"`mapDispatchToProps` must return an object. Instead received %s.",n),n}function y(t,e,r){var n=S(t,e,r);return _.default(v.default(n),"`mergeProps` must return an object. Instead received %s.",n),n}var b=Boolean(r),g=r||x,O=v.default(a)?m.default(a):a||P,S=f||w,R=g.length>1,T=O.length>1,C=j++;return function(r){var a=function(e){function n(t,r){u(this,n),e.call(this,t,r),this.version=C,this.store=t.store||r.store,_.default(this.store,'Could not find "store" in either the context or '+('props of "'+this.constructor.displayName+'". ')+"Either wrap the root component in a , "+('or explicitly pass "store" as a prop to "'+this.constructor.displayName+'".')),this.stateProps=l(this.store,t),this.dispatchProps=d(this.store,t),this.state={props:this.computeNextState()}}return i(n,e),n.prototype.shouldComponentUpdate=function(t,e){return!h.default(this.state.props,e.props)},c(n,null,[{key:"displayName",value:"Connect("+s(r)+")",enumerable:!0},{key:"WrappedComponent",value:r,enumerable:!0},{key:"contextTypes",value:{store:o},enumerable:!0},{key:"propTypes",value:{store:o},enumerable:!0}]),n.prototype.computeNextState=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0];return y(this.stateProps,this.dispatchProps,t)},n.prototype.updateStateProps=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0],e=l(this.store,t);return h.default(e,this.stateProps)?!1:(this.stateProps=e,!0)},n.prototype.updateDispatchProps=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0],e=d(this.store,t);return h.default(e,this.dispatchProps)?!1:(this.dispatchProps=e,!0)},n.prototype.updateState=function(){var t=arguments.length<=0||void 0===arguments[0]?this.props:arguments[0],e=this.computeNextState(t);h.default(e,this.state.props)||this.setState({props:e})},n.prototype.isSubscribed=function(){return"function"==typeof this.unsubscribe},n.prototype.trySubscribe=function(){b&&!this.unsubscribe&&(this.unsubscribe=this.store.subscribe(this.handleChange.bind(this)),this.handleChange())},n.prototype.tryUnsubscribe=function(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null)},n.prototype.componentDidMount=function(){this.trySubscribe()},n.prototype.componentWillReceiveProps=function(t){h.default(t,this.props)||(R&&this.updateStateProps(t),T&&this.updateDispatchProps(t),this.updateState(t))},n.prototype.componentWillUnmount=function(){this.tryUnsubscribe()},n.prototype.handleChange=function(){this.updateStateProps()&&this.updateState()},n.prototype.getWrappedInstance=function(){return this.refs.wrappedInstance},n.prototype.render=function(){return t.createElement(r,p({ref:"wrappedInstance"},this.state.props))},n}(e);return"undefined"!=typeof n&&"undefined"!=typeof n.env,"undefined"!=typeof __DEV__&&__DEV__&&(a.prototype.componentWillUpdate=function(){this.version!==C&&(this.version=C,this.trySubscribe(),this.updateStateProps(),this.updateDispatchProps(),this.updateState())}),a}}}e.__esModule=!0;var c=function(){function t(t,e){for(var r=0;r child into a function."))}function r(){!d&&l&&(d=!0,console.error("With React 0.13, you need to wrap child into a function. This restriction will be removed with React 0.14."))}var n=t.Component,s=t.PropTypes,c=t.Children,f=p.default(s),l=i(t),d=!1;return function(t){function n(e,r){o(this,n),t.call(this,e,r),this.state={store:e.store}}return u(n,t),n.prototype.getChildContext=function(){return{store:this.state.store}},a(n,null,[{key:"childContextTypes",value:{store:f.isRequired},enumerable:!0},{key:"propTypes",value:{store:f.isRequired,children:(l?s.func:s.element).isRequired},enumerable:!0}]),n.prototype.componentWillReceiveProps=function(t){var e=this.state.store,r=t.store;if(e!==r){var n=r.getReducer();e.replaceReducer(n)}},n.prototype.render=function(){var t=this.props.children;return"function"==typeof t?(e(),t=t()):r(),c.only(t)},n}(n)}e.__esModule=!0;var a=function(){function t(t,e){for(var r=0;r1)for(var r=1;rn;n++)t[n]=arguments[n];return t.reduceRight(function(e,t){return t(e)})}t.__esModule=!0,t.default=n,e.exports=t.default},function(e,t){"use strict";function n(e){if(!e||"object"!=typeof e)return!1;var t="function"==typeof e.constructor?Object.getPrototypeOf(e):Object.prototype;if(null===t)return!0;var n=t.constructor;return"function"==typeof n&&n instanceof n&&r(n)===r(Object)}t.__esModule=!0,t.default=n;var r=function(e){return Function.prototype.toString.call(e)};e.exports=t.default},function(e,t){"use strict";function n(e,t){return Object.keys(e).reduce(function(n,r){return n[r]=t(e[r],r),n},{})}t.__esModule=!0,t.default=n,e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function o(){for(var e=arguments.length,t=Array(e),n=0;e>n;n++)t[n]=arguments[n];return function(e){return function(n,r){var o=e(n,r),i=o.dispatch,c=[],f={getState:o.getState,dispatch:function(e){return i(e)}};return c=t.map(function(e){return e(f)}),i=a.default.apply(void 0,c.concat([o.dispatch])),u({},o,{dispatch:i})}}}t.__esModule=!0;var u=Object.assign||function(e){for(var t=1;t0&&console.error("Unexpected "+(r.length>1?"keys":"key")+" "+('"'+r.join('", "')+'" in initialState will be ignored. ')+('Expected to find one of the known reducer keys instead: "'+n.join('", "')+'"'))}function a(e){var t=h.default(e,function(e){return"function"==typeof e});Object.keys(t).forEach(function(e){var n=t[e];if("undefined"==typeof n(void 0,{type:c.ActionTypes.INIT}))throw new Error('Reducer "'+e+'" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.');var r=Math.random().toString(36).substring(7).split("").join(".");if("undefined"==typeof n(void 0,{type:r}))throw new Error('Reducer "'+e+'" returned undefined when probed with a random type. '+("Don't try to handle "+c.ActionTypes.INIT+' or other actions in "redux/*" ')+"namespace. They are considered private. Instead, you must return the current state for any unknown actions, unless it is undefined, in which case you must return the initial state, regardless of the action type. The initial state may not be undefined.")});var n,o=l.default(t,function(){return void 0});return function(e,a){void 0===e&&(e=o);var c=l.default(t,function(t,n){var r=t(e[n],a);if("undefined"==typeof r)throw new Error(u(n,a));return r});return"undefined"!=typeof r&&"undefined"!=typeof r.env,(!1||"undefined"!=typeof __DEV__&&__DEV__)&&(n||(i(e,c),n=!0)),c}}t.__esModule=!0,t.default=a;var c=n(1),f=n(3),s=o(f),d=n(4),l=o(d),p=n(8),h=o(p);e.exports=t.default}).call(t,n(9))},function(e,t){"use strict";function n(e,t){return Object.keys(e).reduce(function(n,r){return t(e[r])&&(n[r]=e[r]),n},{})}t.__esModule=!0,t.default=n,e.exports=t.default},function(e,t){function n(){f=!1,i.length?c=i.concat(c):s=-1,c.length&&r()}function r(){if(!f){var e=setTimeout(n);f=!0;for(var t=c.length;t;){for(i=c,c=[];++s1)for(var n=1;n exception
11 | is_content_type_json?(env) ? build_response(exception) : raise(exception)
12 | end
13 | end
14 |
15 | private
16 |
17 | def is_content_type_json? env
18 | env['CONTENT_TYPE'] =~ /application\/json/
19 | end
20 |
21 | def error_message exception
22 | "Payload data is not valid JSON. Error message: #{exception}"
23 | end
24 |
25 | def build_response exception
26 | [ 400, { "Content-Type" => "application/json" }, [ { error: error_message(exception) }.to_json ] ]
27 | end
28 |
29 | end
30 |
--------------------------------------------------------------------------------
/app/models/comment.rb:
--------------------------------------------------------------------------------
1 | class Comment < ActiveRecord::Base
2 | belongs_to :user
3 | belongs_to :post
4 |
5 | validates_presence_of :user, :post
6 |
7 | def user_name
8 | user.name
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/app/models/contact.rb:
--------------------------------------------------------------------------------
1 | class Contact
2 | include ActiveModel::Model
3 |
4 | attr_accessor :email, :title, :body
5 |
6 | validates :email, :title, presence: true
7 | validates :email, email: true
8 | end
9 |
--------------------------------------------------------------------------------
/app/models/post.rb:
--------------------------------------------------------------------------------
1 | class Post < ActiveRecord::Base
2 | belongs_to :user
3 | has_many :comments
4 |
5 | validates_presence_of :user, :title, :content
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | class User < ActiveRecord::Base
2 |
3 | # Include default devise modules. Others available are:
4 | # :confirmable, :lockable, :timeoutable and :omniauthable
5 | devise :database_authenticatable, :registerable,
6 | :recoverable, :trackable, :validatable, :rememberable, :async
7 |
8 | mount_uploader :profile_image, ProfileImageUploader
9 |
10 | before_save :ensure_authentication_token_is_present
11 |
12 | validates :first_name, :last_name, :email, presence: true
13 | validates :email, uniqueness: true
14 |
15 | has_many :posts
16 | has_many :comments
17 |
18 | def name
19 | [first_name, last_name].join(' ').strip
20 | end
21 |
22 | def super_admin?
23 | role == 'super_admin'
24 | end
25 |
26 | def as_json( options = {} )
27 | new_options = options.merge({ only: [:email, :first_name, :last_name, :current_sign_in_at] })
28 |
29 | super new_options
30 | end
31 |
32 | private
33 |
34 | def ensure_authentication_token_is_present
35 | if authentication_token.blank?
36 | self.authentication_token = generate_authentication_token
37 | end
38 | end
39 |
40 | def generate_authentication_token
41 | loop do
42 | token = Devise.friendly_token
43 | break token unless User.where(authentication_token: token).first
44 | end
45 | end
46 |
47 | end
48 |
--------------------------------------------------------------------------------
/app/services/addition_service.rb:
--------------------------------------------------------------------------------
1 | class AdditionService
2 |
3 | attr_reader :number1, :number2
4 |
5 | def initialize number1, number2
6 | @number1 = number1
7 | @number2 = number2
8 | end
9 |
10 | def process
11 | number1 + number2
12 | end
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/app/uploaders/profile_image_uploader.rb:
--------------------------------------------------------------------------------
1 | class ProfileImageUploader < CarrierWave::Uploader::Base
2 |
3 | storage :file
4 |
5 | def store_dir
6 | "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
7 | end
8 |
9 | def extension_white_list
10 | %w(jpg jpeg png)
11 | end
12 |
13 | def filename
14 | if original_filename.present?
15 | if model && model.read_attribute(mounted_as).present?
16 | model.read_attribute(mounted_as)
17 | else
18 | "#{secure_token}.#{file.extension}"
19 | end
20 | end
21 | end
22 |
23 | protected
24 |
25 | def secure_token
26 | var = :"@#{mounted_as}_secure_token"
27 | model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
28 | end
29 |
30 | end
31 |
--------------------------------------------------------------------------------
/app/views/home/index.html.haml:
--------------------------------------------------------------------------------
1 | %span.home-message
2 | This is home page.
3 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html+phone.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html{lang: "en"}
3 | %head
4 | %meta{charset: "utf-8"}/
5 | %meta{:content => "IE=Edge,chrome=1", "http-equiv" => "X-UA-Compatible"}/
6 | %meta{content: "width=device-width, initial-scale=1.0", name: "viewport"}/
7 | %title= content_for?(:title) ? yield(:title) : "Wheel"
8 | = csrf_meta_tags
9 | / Le HTML5 shim, for IE6-8 support of HTML elements
10 | /[if lt IE 9]
11 |
12 | = stylesheet_link_tag "application_phone", media: "all"
13 | /
14 | /
15 | %body{class: "#{@layout_carrier.class_for_body}"}
16 | .navbar.navbar-default.navbar-static-top{role: "navigation"}
17 | .container
18 | .navbar-header
19 | %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button"}
20 | %span.sr-only Toggle navigation
21 | %span.icon-bar
22 | %span.icon-bar
23 | %span.icon-bar
24 | %a.navbar-brand{href: "/"} Wheel
25 | .navbar-collapse.collapse
26 | = render 'shared/nav'
27 | .container
28 | .row
29 | .col-sm-12
30 | = render 'shared/bootstrap_flash'
31 | = yield
32 | %footer
33 | / for footer
34 | / Placed at the end of the document so the pages load faster
35 | = javascript_include_tag "application_phone"
36 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html{lang: "en"}
3 | %head
4 | %meta{charset: "utf-8"}/
5 | %meta{:content => "IE=Edge,chrome=1", "http-equiv" => "X-UA-Compatible"}/
6 | %meta{content: "width=device-width, initial-scale=1.0", name: "viewport"}/
7 | %title= content_for?(:title) ? yield(:title) : "Wheel"
8 | = csrf_meta_tags
9 | / Le HTML5 shim, for IE6-8 support of HTML elements
10 | /[if lt IE 9]
11 |
12 | = stylesheet_link_tag "application_desktop", media: "all"
13 | /
14 | /
15 | %body{class: "#{@layout_carrier.class_for_body}"}
16 | .navbar.navbar-default.navbar-static-top{role: "navigation"}
17 | .container
18 | .navbar-header
19 | %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button"}
20 | %span.sr-only Toggle navigation
21 | %span.icon-bar
22 | %span.icon-bar
23 | %span.icon-bar
24 | %a.navbar-brand{href: "/"} Wheel
25 | .navbar-collapse.collapse
26 | = render 'shared/nav'
27 | .container.page
28 | .row
29 | .col-sm-12
30 | = render 'shared/bootstrap_flash'
31 | = yield
32 | %footer
33 | / for footer
34 | / Placed at the end of the document so the pages load faster
35 | = javascript_include_tag "application_desktop"
36 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.haml:
--------------------------------------------------------------------------------
1 | !!! Strict
2 | %html{xmlns: "http://www.w3.org/1999/xhtml"}
3 | %head
4 | %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/
5 | %meta{content: "width=device-width", name: "viewport"}/
6 | :css
7 | body {
8 | font-family: sans-serif;
9 | font-size: 14px;
10 | }
11 |
12 | a, a:link {
13 | color: #4c6d8b;
14 | }
15 |
16 | a:hover {
17 | text-decoration: none;
18 | }
19 |
20 | .facebook table td {
21 | background: #3b5998;
22 | border-color: #2d4473;
23 | }
24 |
25 | .facebook:hover table td {
26 | background: #2d4473 !important;
27 | }
28 |
29 | .twitter table td {
30 | background: #00acee;
31 | border-color: #0087bb;
32 | }
33 |
34 | .twitter:hover table td {
35 | background: #0087bb !important;
36 | }
37 |
38 | .google-plus table td {
39 | background-color: #DB4A39;
40 | border-color: #CC0000;
41 | }
42 |
43 | .google-plus:hover table td {
44 | background: #CC0000 !important;
45 | }
46 |
47 | .template-label {
48 | color: #ffffff;
49 | font-weight: bold;
50 | font-size: 11px;
51 | }
52 |
53 | .callout .wrapper {
54 | padding-bottom: 20px;
55 | }
56 |
57 | .callout .panel {
58 | background: #ECF8FF;
59 | border-color: #b9e5ff;
60 | }
61 |
62 | .header {
63 | background: #333333;
64 | }
65 |
66 | .footer .wrapper {
67 | background: #ebebeb;
68 | }
69 |
70 | .footer h5 {
71 | padding-bottom: 10px;
72 | }
73 |
74 | table.columns .text-pad {
75 | padding-left: 10px;
76 | padding-right: 10px;
77 | }
78 |
79 | table.columns .left-text-pad {
80 | padding-left: 10px;
81 | }
82 |
83 | table.columns .right-text-pad {
84 | padding-right: 10px;
85 | }
86 |
87 | hr {
88 | border-bottom: none;
89 | border-left: 0;
90 | border-right: none;
91 | border-top: 1px dotted #999;
92 | }
93 |
94 | h1, .h1 {
95 | line-height: 150%;
96 | }
97 |
98 | @media only screen and (max-width: 600px) {
99 |
100 | table[class="body"] .right-text-pad {
101 | padding-left: 10px !important;
102 | }
103 |
104 | table[class="body"] .left-text-pad {
105 | padding-right: 10px !important;
106 | }
107 | }
108 |
109 | .activity_list {
110 | list-style: none;
111 | margin-left: 0;
112 | padding-left: 0;
113 | }
114 |
115 | .activity_list li {
116 | margin-bottom: 10px;
117 | font-size: 16px;
118 | line-height: 24px;
119 | }
120 |
121 | .detailed_list {
122 | padding-left: 55px;
123 | margin-bottom: 10px;
124 | }
125 |
126 | .detailed_list li {
127 | font-size: 14px;
128 | color: #333;
129 | line-height: 20px;
130 | margin-bottom: 4px;
131 | }
132 |
133 | .date {
134 | font-size: 13px;
135 | font-weight: 700;
136 | }
137 |
138 | .time_heading {
139 | font-size: 14px;
140 | font-weight: 700;
141 | display: block;
142 | height: 20px;
143 | position: relative;
144 | text-align: center;
145 | margin: 30px 0 10px;
146 | padding-top: 20px;
147 | border-top: 1px dotted #dedede;
148 | }
149 |
150 | .time {
151 | padding: 0 5px;
152 | position: relative;
153 | z-index: 1;
154 | }
155 | %body{style: "font-size: 16px !important; line-height: 26px !important;"}
156 | %table.body{style: "width: 100% !important;"}
157 | %tr
158 | %td.center{align: "center", valign: "top"}
159 | %center
160 | %table.row.header{style: "background: #000000 !important; width: 100% !important;"}
161 | %tr
162 | %td.center{align: "center"}
163 | %center
164 | %table.container
165 | %tr
166 | %td.wrapper.last
167 | %table.twelve.columns
168 | %tr
169 | %td.six.sub-columns
170 | %td.six.sub-columns.last
171 | %span.template-label
172 | %table.container
173 | %tr
174 | %td
175 | %table.row
176 | %tr
177 | %td.wrapper.last
178 | %table.twelve.columns
179 | %tr
180 | %td
181 | = yield
182 | %td.expander
183 |
--------------------------------------------------------------------------------
/app/views/layouts/superadmin.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html{lang: "en"}
3 | %head
4 | %meta{charset: "utf-8"}/
5 | %meta{:content => "IE=Edge,chrome=1", "http-equiv" => "X-UA-Compatible"}/
6 | %meta{content: "width=device-width, initial-scale=1.0", name: "viewport"}/
7 | %title= content_for?(:title) ? yield(:title) : "Super Admin"
8 | = csrf_meta_tags
9 | / Le HTML5 shim, for IE6-8 support of HTML elements
10 | /[if lt IE 9]
11 |
12 | = stylesheet_link_tag "application_desktop", media: "all"
13 | /
14 | /
15 | %body
16 | .navbar.navbar-default.navbar-static-top{role: "navigation"}
17 | .container
18 | .navbar-header
19 | %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", :type => "button"}
20 | %span.sr-only Toggle navigation
21 | %span.icon-bar
22 | %span.icon-bar
23 | %span.icon-bar
24 | %a.navbar-brand{href: "/"} Wheel
25 | .navbar-collapse.collapse
26 | = render "shared/superadmin_nav"
27 | .container
28 | .row
29 | .col-sm-12
30 | = render 'shared/bootstrap_flash'
31 | = yield
32 | %footer
33 | / for footer
34 | / Placed at the end of the document so the pages load faster
35 | = javascript_include_tag "application_desktop"
36 |
--------------------------------------------------------------------------------
/app/views/mailer/contact_us_notification.html.haml:
--------------------------------------------------------------------------------
1 | %h3 New contact
2 | %p
3 | %b Email:
4 | = @email
5 | %p
6 | %b Title:
7 | = @title
8 | %p
9 | %b Message:
10 | = @body
11 |
--------------------------------------------------------------------------------
/app/views/pages/about.html+phone.haml:
--------------------------------------------------------------------------------
1 | You are seeing the phone version of the about page.
2 |
--------------------------------------------------------------------------------
/app/views/pages/about.html.haml:
--------------------------------------------------------------------------------
1 | You are seeing the desktop version of the about page.
2 |
--------------------------------------------------------------------------------
/app/views/pages/contact_us.html.haml:
--------------------------------------------------------------------------------
1 | .row{style: "padding-top: 10px;"}
2 | = simple_form_for @contact, html: { class: 'bootstrap-center-form-medium' } do |f|
3 | %h2 Contact us
4 | .form-controls
5 | = f.input :title, required: true, input_html: { class: 'form-control' }
6 | .form-controls
7 | = f.input :email, required: true, input_html: { class: 'form-control' }
8 | .form-controls
9 | = f.input :body, as: :text, input_html: { class: 'form-control', rows: '3' }
10 | .form-buttons
11 | = f.button :submit, 'Send message', class: "btn btn-primary"
12 |
--------------------------------------------------------------------------------
/app/views/pages/index.html.haml:
--------------------------------------------------------------------------------
1 | Listing of All Pages
2 | %br/
3 | = link_to "Contact US", pages_contact_us_path
4 | %br/
5 | = link_to "About", pages_about_path
6 |
--------------------------------------------------------------------------------
/app/views/pages/redux.html.haml:
--------------------------------------------------------------------------------
1 | %div{id: 'redux-root'}
2 |
--------------------------------------------------------------------------------
/app/views/posts/_index.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.array! @posts do |post|
2 | json.id post.id
3 | json.title post.title
4 | json.content post.content
5 | json.url url_for(post)
6 | end
7 |
8 |
--------------------------------------------------------------------------------
/app/views/posts/_show.json.jbuilder:
--------------------------------------------------------------------------------
1 | json.id @post.id
2 | json.title @post.title
3 | json.content @post.content
4 | json.new_comment_url url_for([@post, :comments])
5 |
6 | json.comments @post.comments, :content, :created_at, :user_name
7 |
--------------------------------------------------------------------------------
/app/views/posts/index.html.haml:
--------------------------------------------------------------------------------
1 | = react_component('PostsIndex', posts: (render partial: 'index', formats: [:json]), user_id: current_user.id)
2 |
--------------------------------------------------------------------------------
/app/views/posts/show.html.haml:
--------------------------------------------------------------------------------
1 | = react_component('PostsShow', post: (render partial: 'show', formats: [:json]), user_id: current_user.id)
2 |
--------------------------------------------------------------------------------
/app/views/shared/_bootstrap_flash.html.haml:
--------------------------------------------------------------------------------
1 | - flash.each do |name, message|
2 | - if message.present?
3 | %div{class: "alert alert-#{name.to_s == 'alert' ? "danger" : "success"}"}
4 | %a.close{"data-dismiss" => "alert"} ×
5 | = content_tag :div, message, id: "flash_#{name}" if message.is_a?(String)
6 |
--------------------------------------------------------------------------------
/app/views/shared/_modal.html.haml:
--------------------------------------------------------------------------------
1 | %div{class: "modal", "data-behavior" => "modal-content"}
2 | .modal-dialog
3 | .modal-content
4 | .modal-header
5 | = button_tag '×', :class => "close btn-close-dialog", "data-behavior" => "modal-close", "aria-hidden" => "true"
6 | %h4.modal-title= yield(:modal_title)
7 | .modal-body
8 | = yield(:modal_body)
9 |
--------------------------------------------------------------------------------
/app/views/shared/_nav.html.haml:
--------------------------------------------------------------------------------
1 | %ul.nav.navbar-nav
2 | = nav_link 'Home', root_path
3 | = nav_link 'Redux', pages_redux_path
4 | = nav_link 'About', pages_about_path
5 | = nav_link 'Contact us', pages_contact_us_path
6 | = render('shared/user_right_nav')
7 |
--------------------------------------------------------------------------------
/app/views/shared/_superadmin_nav.html.haml:
--------------------------------------------------------------------------------
1 | %ul.nav.navbar-nav
2 | = nav_link('Users', superadmin_users_path)
3 | = nav_link("Active Admin", active_admin_root_path)
4 | = nav_link('DJ', '/delayed_job', false, "target" => '_blank')
5 | = render('shared/user_right_nav')
6 |
--------------------------------------------------------------------------------
/app/views/shared/_user_is_signed_in.html.haml:
--------------------------------------------------------------------------------
1 | %li.dropdown
2 | %a.dropdown-toggle{"data-toggle" => "dropdown", :href => "#"}
3 | = current_user.name
4 | %b.caret
5 | %ul.dropdown-menu
6 | - if super_admin_signed_in?
7 | = nav_link 'Superadmin', superadmin_root_path
8 | %li.divider
9 | = nav_link 'My account', profile_path
10 | = nav_link 'Change password', password_edit_path
11 | = nav_link 'Logout', destroy_user_session_path, false, method: :delete
12 |
--------------------------------------------------------------------------------
/app/views/shared/_user_right_nav.html.haml:
--------------------------------------------------------------------------------
1 | %ul.nav.navbar-nav.navbar-right
2 | - if user_signed_in?
3 | = render 'shared/user_is_signed_in'
4 | - else
5 | = nav_link 'Sign in', new_session_path(:user)
6 |
--------------------------------------------------------------------------------
/app/views/superadmin/users/_edit_modal.html.haml:
--------------------------------------------------------------------------------
1 | = content_for(:modal_title) do
2 | Edit #{@user_name.to_s.humanize}
3 |
4 | = content_for(:modal_body) do
5 | .row{style: "padding-top: 10px;"}
6 | = simple_form_for(@user, url: superadmin_user_path(@user), |
7 | method: :patch, |
8 | wrapper: :bootstrap3, |
9 | html: { method: :put, class: 'bootstrap-center-form-medium' }) do |f| |
10 | .form-controls
11 | = f.input :email, required: true, |
12 | autofocus: true, |
13 | input_html: { class: 'form-control' } |
14 | = f.input :first_name, required: true, input_html: { class: 'form-control' }
15 | = f.input :last_name, required: true, input_html: { class: 'form-control' }
16 | = f.input :profile_image, as: :file
17 | .form-buttons
18 | = f.button :submit, "Update", class: 'btn btn-primary'
19 |
20 |
21 | = render "shared/modal"
22 |
--------------------------------------------------------------------------------
/app/views/superadmin/users/index.html.haml:
--------------------------------------------------------------------------------
1 | %table.table.table-striped
2 | %thead
3 | %tr
4 | %th Name
5 | %th Email
6 | %th Last signed in
7 | %th
8 | - @users.each do |user|
9 | %tr
10 | %td
11 | = user.name
12 | %td
13 | = user.email
14 | %td
15 | = user.last_sign_in_at
16 | %td
17 | = link_to 'Edit', "#", data: { url: edit_superadmin_user_path(user), behavior: 'display-in-modal' }
18 |
--------------------------------------------------------------------------------
/app/views/users/confirmations/new.html.haml:
--------------------------------------------------------------------------------
1 | %h2 Resend confirmation instructions
2 | = simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
3 | = f.error_notification
4 | = f.full_error :confirmation_token
5 | .form-inputs
6 | = f.input :email, required: true, autofocus: true
7 | .form-actions
8 | = f.button :submit, "Resend confirmation instructions"
9 | = render "users/shared/links"
10 |
--------------------------------------------------------------------------------
/app/views/users/mailer/confirmation_instructions.html.haml:
--------------------------------------------------------------------------------
1 | %p
2 | Welcome #{@email}!
3 | %p You can confirm your account email through the link below:
4 | %p= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token)
5 |
--------------------------------------------------------------------------------
/app/views/users/mailer/reset_password_instructions.html.haml:
--------------------------------------------------------------------------------
1 | %p
2 | Hello #{@resource.email}!
3 | %p Someone has requested a link to change your password. You can do this through the link below.
4 | %p= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token)
5 |
6 | %p If you didn't request this, please ignore this email.
7 | %p Your password won't change until you access the link above and create a new one.
8 |
--------------------------------------------------------------------------------
/app/views/users/mailer/unlock_instructions.html.haml:
--------------------------------------------------------------------------------
1 | %p
2 | Hello #{@resource.email}!
3 | %p Your account has been locked due to an excessive number of unsuccessful sign in attempts.
4 | %p Click the link below to unlock your account:
5 | %p= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token)
6 |
--------------------------------------------------------------------------------
/app/views/users/passwords/edit.html.haml:
--------------------------------------------------------------------------------
1 | .row{style: "padding-top: 10px;"}
2 | = simple_form_for(resource, as: resource_name, |
3 | url: password_path(resource_name), |
4 | wrapper: :bootstrap3, |
5 | html: { method: :put, class: 'bootstrap-center-form-medium' }) do |f| |
6 | %h2 Change your password
7 | = f.input :reset_password_token, as: :hidden, input_html: { class: 'form-control' }
8 | .form-controls
9 | = f.full_error :reset_password_token
10 | .form-controls
11 | = f.input :password, label: "New password", |
12 | required: true, |
13 | autofocus: true, |
14 | input_html: { class: 'form-control' } |
15 |
16 | = f.input :password_confirmation, label: "Confirm your new password", |
17 | required: true, |
18 | input_html: { class: 'form-control' } |
19 | .form-buttons
20 | = f.button :submit, "Change my password", class: 'btn-primary'
21 | .devise-links
22 | = render "users/shared/links"
23 |
--------------------------------------------------------------------------------
/app/views/users/passwords/new.html.haml:
--------------------------------------------------------------------------------
1 | .row{style: "padding-top: 10px;"}
2 | = simple_form_for(resource, as: resource_name, |
3 | url: password_path(resource_name), |
4 | wrapper: :bootstrap3, |
5 | html: { method: :post, class: 'bootstrap-center-form-medium' }) do |f| |
6 | %h2 Forgot your password?
7 | .form-controls
8 | = f.input :email, required: true, autofocus: true, input_html: { class: 'form-control' }
9 | .form-buttons
10 | = f.button :submit, "Send me reset password instructions", class: 'btn btn-primary'
11 | .devise-links
12 | = render "users/shared/links"
13 |
--------------------------------------------------------------------------------
/app/views/users/registrations/edit.html.haml:
--------------------------------------------------------------------------------
1 | .row{style: "padding-top: 10px;"}
2 | = simple_form_for(resource, as: resource_name, |
3 | url: profile_update_path, |
4 | wrapper: :bootstrap3, |
5 | html: { method: :put, class: 'bootstrap-center-form-medium' }) do |f| |
6 | %h2
7 | Edit #{resource_name.to_s.humanize}
8 | .form-controls
9 | = f.input :email, required: true, |
10 | autofocus: true, |
11 | input_html: { class: 'form-control' } |
12 | - if devise_mapping.confirmable? && resource.pending_reconfirmation?
13 | %p
14 | Currently waiting confirmation for: #{resource.unconfirmed_email}
15 | = f.input :first_name, required: true, input_html: { class: 'form-control' }
16 | = f.input :last_name, required: true, input_html: { class: 'form-control' }
17 | = f.input :profile_image, as: :file
18 | = f.input :current_password, required: true, |
19 | hint: "we need your current password to confirm your changes", |
20 | input_html: { class: 'form-control' } |
21 | .form-buttons
22 | = f.button :submit, "Update", class: 'btn btn-primary'
23 |
--------------------------------------------------------------------------------
/app/views/users/registrations/edit_password.html.haml:
--------------------------------------------------------------------------------
1 | .row{style: "padding-top: 10px;"}
2 | = simple_form_for(resource, as: resource_name, |
3 | url: password_update_path, |
4 | wrapper: :bootstrap3, |
5 | html: { method: :put, class: 'bootstrap-center-form-medium' }) do |f| |
6 | %h2 Change password
7 | .form-controls
8 | = f.input :password, required: true, |
9 | autofocus: true, |
10 | input_html: { class: 'form-control' } |
11 |
12 | = f.input :password_confirmation, required: true, input_html: { class: 'form-control' }
13 | %hr/
14 | = f.input :current_password, required: true, |
15 | hint: "we need your current password to confirm your changes", |
16 | input_html: { class: 'form-control' } |
17 | .form-buttons
18 | = f.button :submit, "Update", class: 'btn btn-primary'
19 |
--------------------------------------------------------------------------------
/app/views/users/registrations/new.html.haml:
--------------------------------------------------------------------------------
1 | .row{style: "padding-top: 10px;"}
2 | = simple_form_for(resource, as: resource_name, |
3 | url: registration_path(resource_name), |
4 | wrapper: :bootstrap3, |
5 | html: { class: 'bootstrap-center-form-medium' }) do |f| |
6 | %h2 Sign up
7 | .form-controls
8 | = f.input :email, required: true, autofocus: true, input_html: { class: 'form-control' }
9 | = f.input :first_name, required: true, input_html: { class: 'form-control' }
10 | = f.input :last_name, required: true, input_html: { class: 'form-control' }
11 | = f.input :password, required: true, input_html: { class: 'form-control' }
12 | = f.input :password_confirmation, required: true, input_html: { class: 'form-control' }
13 | .form-buttons
14 | = f.button :submit, "Sign up", class: 'btn btn-primary'
15 | .devise-links
16 | = render "users/shared/links"
17 |
--------------------------------------------------------------------------------
/app/views/users/sessions/new.html.haml:
--------------------------------------------------------------------------------
1 | .row{style: "padding-top: 10px;"}
2 | = simple_form_for(resource, as: resource_name, |
3 | url: session_path(resource_name), |
4 | wrapper: :bootstrap3, |
5 | html: { class: 'bootstrap-center-form-medium' }) do |f| |
6 | %h2 Please Sign in
7 | .form-controls
8 | = f.input :email, placeholder: 'Email address', label: false, autofocus: true, input_html: { class: 'form-control' }
9 | = f.input :password, placeholder: 'Password', label: false, input_html: { class: 'form-control' }
10 | - if devise_mapping.rememberable?
11 | = f.input :remember_me, as: :boolean, wrapper: :default
12 | .form-buttons
13 | = f.button :submit, "Sign in", class: 'btn btn-primary'
14 | .devise-links
15 | = render "users/shared/links"
16 |
--------------------------------------------------------------------------------
/app/views/users/shared/_links.haml:
--------------------------------------------------------------------------------
1 | - if controller_name != 'sessions'
2 | = link_to "Sign in", new_session_path(resource_name)
3 | %br/
4 | - if devise_mapping.registerable? && controller_name != 'registrations'
5 | = link_to "Sign up", new_registration_path(resource_name)
6 | %br/
7 | - if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations'
8 | = link_to "Forgot your password?", new_password_path(resource_name)
9 | %br/
10 | - if devise_mapping.confirmable? && controller_name != 'confirmations'
11 | = link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name)
12 | %br/
13 | - if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks'
14 | = link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name)
15 | %br/
16 | - if devise_mapping.omniauthable?
17 | - resource_class.omniauth_providers.each do |provider|
18 | = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider)
19 | %br/
20 |
--------------------------------------------------------------------------------
/app/views/users/unlocks/new.html.haml:
--------------------------------------------------------------------------------
1 | %h2 Resend unlock instructions
2 | = form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f|
3 | = devise_error_messages!
4 | %div
5 | = f.label :email
6 | %br/
7 | = f.email_field :email, autofocus: true
8 | %div
9 | = f.submit "Resend unlock instructions"
10 | = render "users/shared/links"
11 |
--------------------------------------------------------------------------------
/app/workers/base_worker.rb:
--------------------------------------------------------------------------------
1 | class BaseWorker
2 |
3 | def perform
4 | Honeybadger.context(job_name: self.class.name, app_name: Rails.application.engine_name)
5 | end
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/app/workers/event_notification_worker.rb:
--------------------------------------------------------------------------------
1 | class EventNotificationWorker < BaseWorker
2 |
3 | def perform
4 | super
5 |
6 | # do the business stuff
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/delayed_job:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
4 | require 'delayed/command'
5 | Delayed::Command.new(ARGV).daemonize
6 |
--------------------------------------------------------------------------------
/bin/honeybadger:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
4 | require 'honeybadger/cli'
5 | Honeybadger::CLI.start(ARGV)
6 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path('../../config/application', __FILE__)
3 | require_relative '../config/boot'
4 | require 'rails/commands'
5 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 |
4 | # path to your application root.
5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6 |
7 | Dir.chdir APP_ROOT do
8 | # This script is a starting point to setup your application.
9 | # Add necessary setup steps to this file:
10 |
11 | puts "== Installing dependencies =="
12 | system "gem install bundler --conservative"
13 | system "bundle check || bundle install"
14 |
15 | # puts "\n== Copying sample files =="
16 | # unless File.exist?("config/database.yml")
17 | # system "cp config/database.yml.sample config/database.yml"
18 | # end
19 |
20 | puts "\n== Preparing database =="
21 | system "bin/rake db:setup"
22 |
23 | puts "\n== Removing old logs and tempfiles =="
24 | system "rm -f log/*"
25 | system "rm -rf tmp/cache"
26 |
27 | puts "\n== Restarting application server =="
28 | system "touch tmp/restart.txt"
29 | end
30 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads spring without using Bundler, in order to be fast
4 | # It gets overwritten when you run the `spring binstub` command
5 |
6 | unless defined?(Spring)
7 | require "rubygems"
8 | require "bundler"
9 |
10 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ spring \((.*?)\)$.*?^$/m)
11 | ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR)
12 | ENV["GEM_HOME"] = ""
13 | Gem.paths = ENV
14 |
15 | gem "spring", match[1]
16 | require "spring/binstub"
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | ## Customize the test machine
2 | machine:
3 |
4 | timezone:
5 | America/New_York # List of timezones http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
6 |
7 | # Version of ruby to use
8 | ruby:
9 | version:
10 | 2.2.2
11 |
12 | ## Customize database setup
13 | database:
14 | override:
15 | # replace Circle's generated database.yml
16 | - cp config/database.yml.ci config/database.yml
17 | - bundle exec rake db:create db:schema:load --trace
18 |
19 | test:
20 | minitest_globs:
21 | - test/**/*_test.rb
22 |
--------------------------------------------------------------------------------
/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 Rails.application
5 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 | require 'marginalia/railtie'
5 |
6 | # Require the gems listed in Gemfile, including any gems
7 | # you've limited to :test, :development, or :production.
8 | Bundler.require(*Rails.groups)
9 |
10 | module Wheel
11 | class Application < Rails::Application
12 | # Settings in config/environments/* take precedence over those specified here.
13 | # Application configuration should go into files in config/initializers
14 | # -- all .rb files in that directory are automatically loaded.
15 |
16 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
17 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
18 | # config.time_zone = 'Central Time (US & Canada)'
19 |
20 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
21 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
22 | # config.i18n.default_locale = :de
23 |
24 | # Do not swallow errors in after_commit/after_rollback callbacks.
25 | config.active_record.raise_in_transactional_callbacks = true
26 |
27 | config.react.addons = true # defaults to false
28 |
29 | config.react.jsx_transform_options = {
30 | blacklist: ['spec.functionName', 'validation.react', 'strict'],
31 | stage: 0
32 | }
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 |
--------------------------------------------------------------------------------
/config/database.yml.ci:
--------------------------------------------------------------------------------
1 | test:
2 | host: localhost
3 | username: ubuntu
4 | database: circle_ruby_test
5 | adapter: postgresql
6 | pool: 5
7 |
--------------------------------------------------------------------------------
/config/database.yml.postgresql:
--------------------------------------------------------------------------------
1 | <% branch_name = `git symbolic-ref HEAD 2>/dev/null`.chomp.sub('refs/heads/', '') %>
2 | <% repository_name = `git rev-parse --show-toplevel`.split('/').last.strip %>
3 |
4 | development:
5 | adapter: postgresql
6 | encoding: unicode
7 | database: <%= repository_name %>_development
8 | pool: 5
9 | username: postgres
10 | password:
11 |
12 | test:
13 | adapter: postgresql
14 | encoding: unicode
15 | database: <%= repository_name %>_test
16 | pool: 5
17 | username: postgres
18 | password:
19 |
--------------------------------------------------------------------------------
/config/database.yml.postgresqlapp:
--------------------------------------------------------------------------------
1 | <% branch_name = `git symbolic-ref HEAD 2>/dev/null`.chomp.sub('refs/heads/', '') %>
2 | <% repository_name = `git rev-parse --show-toplevel`.split('/').last.strip %>
3 |
4 | # Check doc/why_database_name_only_63_characters_long.md to see
5 | # details about the restriction on database name
6 |
7 | # If you prefer to have branch name in the database name then use following
8 | # database: <%= "#{repository_name}_development_#{branch_name}"[0...63] %>
9 |
10 | development:
11 | adapter: postgresql
12 | database: <%= "#{repository_name}_development"[0...63] %>
13 | host: localhost
14 | pool: 5
15 |
16 | test:
17 | adapter: postgresql
18 | database: <%= "#{repository_name}_test"[0...63] %>
19 | host: localhost
20 | pool: 5
21 |
--------------------------------------------------------------------------------
/config/database.yml.sqlite3:
--------------------------------------------------------------------------------
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 | #
7 | default: &default
8 | adapter: sqlite3
9 | pool: 5
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | database: db/development.sqlite3
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: db/test.sqlite3
22 |
23 | production:
24 | <<: *default
25 | database: db/production.sqlite3
26 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.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 | # Do not eager load code on boot.
10 | config.eager_load = false
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 | # Don't care if the mailer can't send.
17 | config.action_mailer.raise_delivery_errors = false
18 |
19 | # Print deprecation notices to the Rails logger.
20 | config.active_support.deprecation = :log
21 |
22 | # Raise an error on page load if there are pending migrations.
23 | config.active_record.migration_error = :page_load
24 |
25 | # Debug mode disables concatenation and preprocessing of assets.
26 | # This option may cause significant delays in view rendering with a large
27 | # number of complex assets.
28 | config.assets.debug = true
29 |
30 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
31 | # yet still be able to expire them through the digest params.
32 | config.assets.digest = true
33 |
34 | # Adds additional error checking when serving assets at runtime.
35 | # Checks for improperly declared sprockets dependencies.
36 | # Raises helpful error messages.
37 | config.assets.raise_runtime_errors = true
38 |
39 | # Raises error for missing translations
40 | # config.action_view.raise_on_missing_translations = true
41 | end
42 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.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 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application
18 | # Add `rack-cache` to your Gemfile before enabling this.
19 | # For large-scale production use, consider using a caching reverse proxy like
20 | # NGINX, varnish or squid.
21 | # config.action_dispatch.rack_cache = true
22 |
23 | # Disable serving static files from the `/public` folder by default since
24 | # Apache or NGINX already handles this.
25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
26 |
27 | # Compress JavaScripts and CSS.
28 | config.assets.js_compressor = :uglifier
29 | # config.assets.css_compressor = :sass
30 |
31 | # Do not fallback to assets pipeline if a precompiled asset is missed.
32 | config.assets.compile = false
33 |
34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
35 | # yet still be able to expire them through the digest params.
36 | config.assets.digest = true
37 |
38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
39 |
40 | # Specifies the header that your server uses for sending files.
41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
43 |
44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
45 | # config.force_ssl = true
46 |
47 | # Use the lowest log level to ensure availability of diagnostic information
48 | # when problems arise.
49 | config.log_level = :debug
50 |
51 | # Prepend all log lines with the following tags.
52 | # config.log_tags = [ :subdomain, :uuid ]
53 |
54 | # Use a different logger for distributed setups.
55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
56 |
57 | # Use a different cache store in production.
58 | # config.cache_store = :mem_cache_store
59 |
60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
61 | # config.action_controller.asset_host = 'http://assets.example.com'
62 |
63 | # Ignore bad email addresses and do not raise email delivery errors.
64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
65 | # config.action_mailer.raise_delivery_errors = false
66 |
67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
68 | # the I18n.default_locale when a translation cannot be found).
69 | config.i18n.fallbacks = true
70 |
71 | # Send deprecation notices to registered listeners.
72 | config.active_support.deprecation = :notify
73 |
74 | # Use default logging formatter so that PID and timestamp are not suppressed.
75 | config.log_formatter = ::Logger::Formatter.new
76 |
77 | # Do not dump schema after migrations.
78 | config.active_record.dump_schema_after_migration = false
79 | end
80 |
--------------------------------------------------------------------------------
/config/environments/staging.rb:
--------------------------------------------------------------------------------
1 | Wheel::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 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both thread web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application
18 | # Add `rack-cache` to your Gemfile before enabling this.
19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
20 | # config.action_dispatch.rack_cache = true
21 |
22 | # Disable Rails's static asset server (Apache or nginx will already do this).
23 | config.serve_static_files = true
24 |
25 | # Compress JavaScripts and CSS.
26 | config.assets.js_compressor = :uglifier
27 | # config.assets.css_compressor = :sass
28 |
29 | # Do not fallback to assets pipeline if a precompiled asset is missed.
30 | config.assets.compile = false
31 |
32 | # Generate digests for assets URLs.
33 | config.assets.digest = true
34 |
35 | # Version of your assets, change this if you want to expire all your assets.
36 | config.assets.version = '1.0'
37 |
38 | # Specifies the header that your server uses for sending files.
39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
41 |
42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
43 | # config.force_ssl = true
44 |
45 | # Set to :debug to see everything in the log.
46 | config.log_level = :debug
47 |
48 | # Prepend all log lines with the following tags.
49 | # config.log_tags = [ :subdomain, :uuid ]
50 |
51 | # Use a different logger for distributed setups.
52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
53 |
54 | # Use a different cache store in production.
55 | # config.cache_store = :dalli_store
56 |
57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
58 | # config.action_controller.asset_host = "http://assets.example.com"
59 |
60 | # Precompile additional assets.
61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
62 | # config.assets.precompile += %w( search.js )
63 |
64 | # Ignore bad email addresses and do not raise email delivery errors.
65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
66 | # config.action_mailer.raise_delivery_errors = false
67 |
68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
69 | # the I18n.default_locale when a translation can not be found).
70 | config.i18n.fallbacks = true
71 |
72 | # Send deprecation notices to registered listeners.
73 | config.active_support.deprecation = :notify
74 |
75 | # Disable automatic flushing of the log to improve performance.
76 | # config.autoflush_log = false
77 |
78 | # Use default logging formatter so that PID and timestamp are not suppressed.
79 | config.log_formatter = ::Logger::Formatter.new
80 | end
81 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.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 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure static file server for tests with Cache-Control for performance.
16 | config.serve_static_files = true
17 | config.static_cache_control = 'public, max-age=3600'
18 |
19 | # Show full error reports and disable caching.
20 | config.consider_all_requests_local = true
21 | config.action_controller.perform_caching = false
22 |
23 | # Raise exceptions instead of rendering exception templates.
24 | config.action_dispatch.show_exceptions = false
25 |
26 | # Disable request forgery protection in test environment.
27 | config.action_controller.allow_forgery_protection = false
28 |
29 | # Tell Action Mailer not to deliver emails to the real world.
30 | # The :test delivery method accumulates sent emails in the
31 | # ActionMailer::Base.deliveries array.
32 | config.action_mailer.delivery_method = :test
33 |
34 | # Randomize the order test cases are executed.
35 | config.active_support.test_order = :random
36 |
37 | # Print deprecation notices to the stderr.
38 | config.active_support.deprecation = :stderr
39 |
40 | # Raises error for missing translations
41 | # config.action_view.raise_on_missing_translations = true
42 | end
43 |
--------------------------------------------------------------------------------
/config/honeybadger.yml:
--------------------------------------------------------------------------------
1 | ---
2 | api_key: <%= Rails.application.secrets.honeybadger_api_key %>
3 |
--------------------------------------------------------------------------------
/config/initializers/active_admin.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin.setup do |config|
2 |
3 | # == Site Title
4 | #
5 | # Set the title that is displayed on the main layout
6 | # for each of the active admin pages.
7 | #
8 | config.site_title = "Back to App"
9 |
10 | # Set the link url for the title. For example, to take
11 | # users to your main site. Defaults to no link.
12 | #
13 | config.site_title_link = "/superadmin"
14 |
15 | # Set an optional image to be displayed for the header
16 | # instead of a string (overrides :site_title)
17 | #
18 | # Note: Aim for an image that's 21px high so it fits in the header.
19 | #
20 | # config.site_title_image = "logo.png"
21 |
22 | # == Default Namespace
23 | #
24 | # Set the default namespace each administration resource
25 | # will be added to.
26 | #
27 | # eg:
28 | config.default_namespace = :active_admin
29 | config.namespace :active_admin do |active_admin|
30 | active_admin.root_to = 'dashboard#index'
31 | end
32 | #
33 | # This will create resources in the HelloWorld module and
34 | # will namespace routes to /hello_world/*
35 | #
36 | # To set no namespace by default, use:
37 | # config.default_namespace = false
38 | #
39 | # Default:
40 | # config.default_namespace = :admin
41 | #
42 | # You can customize the settings for each namespace by using
43 | # a namespace block. For example, to change the site title
44 | # within a namespace:
45 | #
46 | # config.namespace :admin do |admin|
47 | # admin.site_title = "Custom Admin Title"
48 | # end
49 | #
50 | # This will ONLY change the title for the admin section. Other
51 | # namespaces will continue to use the main "site_title" configuration.
52 |
53 | # == User Authentication
54 | #
55 | # Active Admin will automatically call an authentication
56 | # method in a before filter of all controller actions to
57 | # ensure that there is a currently logged in admin user.
58 | #
59 | # This setting changes the method which Active Admin calls
60 | # within the controller.
61 | config.authentication_method = :ensure_current_user_is_superadmin!
62 |
63 | # == User Authorization
64 | #
65 | # Active Admin will automatically call an authorization
66 | # method in a before filter of all controller actions to
67 | # ensure that there is a user with proper rights. You can use
68 | # CanCanAdapter or make your own. Please refer to documentation.
69 | # config.authorization_adapter = ActiveAdmin::CanCanAdapter
70 |
71 | # You can customize your CanCan Ability class name here.
72 | # config.cancan_ability_class = "Ability"
73 |
74 | # You can specify a method to be called on unauthorized access.
75 | # This is necessary in order to prevent a redirect loop which happens
76 | # because, by default, user gets redirected to Dashboard. If user
77 | # doesn't have access to Dashboard, he'll end up in a redirect loop.
78 | # Method provided here should be defined in application_controller.rb.
79 | # config.on_unauthorized_access = :access_denied
80 |
81 | # == Current User
82 | #
83 | # Active Admin will associate actions with the current
84 | # user performing them.
85 | #
86 | # This setting changes the method which Active Admin calls
87 | # to return the currently logged in user.
88 | config.current_user_method = :current_user
89 |
90 |
91 | # == Logging Out
92 | #
93 | # Active Admin displays a logout link on each screen. These
94 | # settings configure the location and method used for the link.
95 | #
96 | # This setting changes the path where the link points to. If it's
97 | # a string, the strings is used as the path. If it's a Symbol, we
98 | # will call the method to return the path.
99 | #
100 | # Default:
101 | config.logout_link_path = :logout_path
102 |
103 | # This setting changes the http method used when rendering the
104 | # link. For example :get, :delete, :put, etc..
105 | #
106 | # Default:
107 | # config.logout_link_method = :get
108 |
109 |
110 | # == Root
111 | #
112 | # Set the action to call for the root path. You can set different
113 | # roots for each namespace.
114 | #
115 | # Default:
116 | # config.root_to = 'dashboard#index'
117 |
118 |
119 | # == Admin Comments
120 | #
121 | # This allows your users to comment on any resource registered with Active Admin.
122 | #
123 | # You can completely disable comments:
124 | config.comments = false
125 | #
126 | # You can disable the menu item for the comments index page:
127 | # config.show_comments_in_menu = false
128 | #
129 | # You can change the name under which comments are registered:
130 | # config.comments_registration_name = 'AdminComment'
131 |
132 |
133 | # == Batch Actions
134 | #
135 | # Enable and disable Batch Actions
136 | #
137 | config.batch_actions = true
138 |
139 |
140 | # == Controller Filters
141 | #
142 | # You can add before, after and around filters to all of your
143 | # Active Admin resources and pages from here.
144 | #
145 | # config.before_filter :do_something_awesome
146 |
147 |
148 | # == Setting a Favicon
149 | #
150 | # config.favicon = '/assets/favicon.ico'
151 |
152 |
153 | # == Register Stylesheets & Javascripts
154 | #
155 | # We recommend using the built in Active Admin layout and loading
156 | # up your own stylesheets / javascripts to customize the look
157 | # and feel.
158 | #
159 | # To load a stylesheet:
160 | config.register_stylesheet 'common/active_admin'
161 | #
162 | # You can provide an options hash for more control, which is passed along to stylesheet_link_tag():
163 | # config.register_stylesheet 'my_print_stylesheet.css', :media => :print
164 | #
165 | # To load a javascript file:
166 | # config.register_javascript 'my_javascript.js'
167 |
168 |
169 | # == CSV options
170 | #
171 | # Set the CSV builder separator
172 | # config.csv_options = { :col_sep => ';' }
173 | #
174 | # Force the use of quotes
175 | # config.csv_options = { :force_quotes => true }
176 |
177 |
178 | # == Menu System
179 | #
180 | # You can add a navigation menu to be used in your application, or configure a provided menu
181 | #
182 | # To change the default utility navigation to show a link to your website & a logout btn
183 | #
184 | # config.namespace :admin do |admin|
185 | # admin.build_menu :utility_navigation do |menu|
186 | # menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank }
187 | # admin.add_logout_button_to_menu menu
188 | # end
189 | # end
190 | #
191 | # If you wanted to add a static menu item to the default menu provided:
192 | #
193 | # config.namespace :admin do |admin|
194 | # admin.build_menu :default do |menu|
195 | # menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank }
196 | # end
197 | # end
198 |
199 |
200 | # == Download Links
201 | #
202 | # You can disable download links on resource listing pages,
203 | # or customize the formats shown per namespace/globally
204 | #
205 | # To disable/customize for the :admin namespace:
206 | #
207 | # config.namespace :admin do |admin|
208 | #
209 | # # Disable the links entirely
210 | # admin.download_links = false
211 | #
212 | # # Only show XML & PDF options
213 | # admin.download_links = [:xml, :pdf]
214 | #
215 | # # Enable/disable the links based on block
216 | # # (for example, with cancan)
217 | # admin.download_links = proc { can?(:view_download_links) }
218 | #
219 | # end
220 |
221 |
222 | # == Pagination
223 | #
224 | # Pagination is enabled by default for all resources.
225 | # You can control the default per page count for all resources here.
226 | #
227 | # config.default_per_page = 30
228 |
229 |
230 | # == Filters
231 | #
232 | # By default the index screen includes a “Filters” sidebar on the right
233 | # hand side with a filter for each attribute of the registered model.
234 | # You can enable or disable them for all resources here.
235 | #
236 | # config.filters = true
237 |
238 | end
239 |
--------------------------------------------------------------------------------
/config/initializers/asset_precompile.rb:
--------------------------------------------------------------------------------
1 | Rails.application.config.assets.precompile += [ 'application_desktop.css',
2 | 'application_phone.css',
3 | 'application_desktop.js',
4 | 'application_phone.js']
5 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = '1.0'
5 |
6 | # Precompile additional assets.
7 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
8 | Rails.application.config.assets.precompile += %w( common/active_admin.css )
9 |
--------------------------------------------------------------------------------
/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/carrierwave.rb:
--------------------------------------------------------------------------------
1 | require 'carrierwave/orm/activerecord'
2 |
3 | def setup_for_storing_assets_in_file_system
4 | CarrierWave.configure do |config|
5 | config.permissions = 0600
6 | config.directory_permissions = 0700
7 | config.storage = :file
8 | config.asset_host = Rails.application.secrets.host
9 | end
10 | end
11 |
12 | def setup_for_storing_assets_in_test_env
13 | CarrierWave.configure do |config|
14 | config.root = Rails.root.join('tmp')
15 | config.storage = :file
16 | config.enable_processing = false
17 | end
18 | end
19 |
20 | def setup_for_storing_assets_in_s3
21 | CarrierWave.configure do |config|
22 | config.root = Rails.root.join('tmp')
23 | config.fog_credentials = {
24 | provider: 'AWS',
25 | aws_access_key_id: Rails.application.secrets.aws_s3['access_key_id'],
26 | aws_secret_access_key: Rails.application.secrets.aws_s3['secret_access_key'],
27 | region: 'us-west-2'
28 | }
29 | config.fog_directory = Rails.application.secrets.aws_s3['bucket_name']
30 | config.fog_public = true
31 | config.fog_attributes = { 'Cache-Control' => 'max-age=315576000' }
32 | config.storage = :fog
33 | config.cache_dir = 'carrierwave'
34 | end
35 | end
36 |
37 | if Rails.env == 'test'
38 | setup_for_storing_assets_in_test_env
39 | else
40 | case Rails.application.secrets.store_uploaded_assets_in
41 | when 'aws_s3'
42 | setup_for_storing_assets_in_s3
43 | when 'filesystem'
44 | setup_for_storing_assets_in_file_system
45 | else
46 | raise "Please configure 'store_uploaded_assets_in' in config/secrets.yml"
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/config/initializers/catch_json_parser_errors.rb:
--------------------------------------------------------------------------------
1 | unless Rails.env.development?
2 | Rails.application.config.middleware.insert_before ActionDispatch::ParamsParser, "CatchJsonParseErrors"
3 | end
4 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.action_dispatch.cookies_serializer = :json
4 |
--------------------------------------------------------------------------------
/config/initializers/delayed_job_config.rb:
--------------------------------------------------------------------------------
1 | Delayed::Worker.destroy_failed_jobs = false
2 |
3 | # Amount of time to sleep when no jobs are found. You can easily set it to 5 seconds or less.
4 | Delayed::Worker.sleep_delay = 5
5 |
6 | # If the work takes more than x minutes then DJ will abort
7 | Delayed::Worker.max_run_time = 5.minutes
8 |
9 | Delayed::Worker.read_ahead = 10
10 |
11 | Delayed::Worker.delay_jobs = !Rails.env.test?
12 |
13 | # In production have default number of attempts ( which I think is 30 )
14 | if !Rails.env.production?
15 | Delayed::Worker.max_attempts = 3
16 | end
17 |
--------------------------------------------------------------------------------
/config/initializers/delayed_job_invoke_worker_automatically.rb:
--------------------------------------------------------------------------------
1 | # This code automatically fires background job worker in heroku even if there
2 | # is no explicit worker. This technique works ok for non production branches. For production
3 | # instance use a dedicated worker provided by heroku ( it costs money ).
4 | #
5 | # This feature should not be confused with `worker: bundle exec rake jobs:work` entry in the `Procfile`.
6 | # If a heroku instance does not have any worker then that entry in the `Procfile` will not do anything.
7 | # The technique employed here spawns a new process from the dyno process and that spawned process
8 | # acts like a background job processor.
9 | #
10 | # For this feature to work ensure that ENV['INVOKE_WORKER_AUTOMATICALLY'] is set to 'enabled' in feature
11 | # branches. In production environemnt either do not have ENV['INVOKE_WORKER_AUTOMATICALLY'] entry or
12 | # if you have an entry then set the value to 'disabled`.
13 |
14 |
15 | # We try not to make code behave differently depending on Rails environemt but this is an exception.
16 | unless Rails.env.production?
17 |
18 | # $PROGRAM_NAME check is needed here to successfully run migrations
19 | if !($PROGRAM_NAME =~ /(rake)(.rb)?$/) &&
20 | ENV['INVOKE_WORKER_AUTOMATICALLY'] &&
21 | ENV['INVOKE_WORKER_AUTOMATICALLY'] == 'enabled'
22 |
23 | pid = spawn('INVOKE_WORKER_AUTOMATICALLY=disabled bundle exec rake jobs:work')
24 | Process.detach(pid)
25 | end
26 |
27 | end
28 |
--------------------------------------------------------------------------------
/config/initializers/devise_async.rb:
--------------------------------------------------------------------------------
1 | Devise::Async.setup do |config|
2 | config.backend = :delayed_job
3 | config.priority = -1
4 | end
--------------------------------------------------------------------------------
/config/initializers/email_interceptor.rb:
--------------------------------------------------------------------------------
1 | if Rails.application.secrets.intercept_and_forward_emails_to.present?
2 | options = { forward_emails_to: Rails.application.secrets.intercept_and_forward_emails_to,
3 | deliver_emails_to: ['@example.com'] }
4 |
5 | interceptor = MailInterceptor::Interceptor.new(options)
6 | ActionMailer::Base.register_interceptor(interceptor)
7 | end
8 |
--------------------------------------------------------------------------------
/config/initializers/email_prefixer.rb:
--------------------------------------------------------------------------------
1 | EmailPrefixer.configure do |config|
2 | config.stage_name = 'WHEEL'
3 | end
4 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/config/initializers/honeybadger.rb:
--------------------------------------------------------------------------------
1 | # When a DelayedJob operation fails then honeybadger should collect
2 | # contextual information like job name and the host.
3 | class HoneybadgerDelayedJobPlugin < Delayed::Plugin
4 | callbacks do |lifecycle|
5 | lifecycle.before(:invoke_job) do |job, *args, &block|
6 | Honeybadger.context(job_name: job.name, host: Rails.application.secrets.host)
7 | end
8 | end
9 | end
10 |
11 | Delayed::Worker.plugins << HoneybadgerDelayedJobPlugin
12 |
--------------------------------------------------------------------------------
/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. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/marginalia.rb:
--------------------------------------------------------------------------------
1 | Marginalia.application_name = 'WHEEL'
2 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/config/initializers/rack_deflater.rb:
--------------------------------------------------------------------------------
1 | Rails.application.config.middleware.use Rack::Deflater
2 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_wheel_session'
4 |
--------------------------------------------------------------------------------
/config/initializers/setup_email.rb:
--------------------------------------------------------------------------------
1 | ActionMailer::Base.default_url_options[:host] = Rails.application.secrets.host
2 |
3 | ActionMailer::Base.delivery_method = Rails.application.secrets.mailer_delivery_method
4 |
5 | if ActionMailer::Base.delivery_method == :smtp
6 | ActionMailer::Base.smtp_settings = Rails.application.secrets.mailer['smtp_settings'].symbolize_keys
7 | end
8 |
--------------------------------------------------------------------------------
/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-danger'
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 the native HTML5 validations (novalidate form option).
110 | # These validations are enabled in SimpleForm's internal config but disabled by default
111 | # in this configuration, which is recommended due to some quirks from different browsers.
112 | # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
113 | # change this configuration to true.
114 | config.browser_validations = false
115 |
116 | # Collection of methods to detect if a file type was given.
117 | # config.file_methods = [ :mounted_as, :file?, :public_filename ]
118 |
119 | # Custom mappings for input types. This should be a hash containing a regexp
120 | # to match as key, and the input type that will be used when the field name
121 | # matches the regexp as value.
122 | # config.input_mappings = { /count/ => :integer }
123 |
124 | # Custom wrappers for input types. This should be a hash containing an input
125 | # type as key and the wrapper that will be used for all inputs with specified type.
126 | # config.wrapper_mappings = { string: :prepend }
127 |
128 | # Default priority for time_zone inputs.
129 | # config.time_zone_priority = nil
130 |
131 | # Default priority for country inputs.
132 | # config.country_priority = nil
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 |
143 | # Default class for inputs
144 | # config.input_class = nil
145 | end
146 |
--------------------------------------------------------------------------------
/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 :bootstrap3,
15 | tag: 'div',
16 | class: 'form-group',
17 | error_class: 'has-error' do |b|
18 |
19 | b.use :html5
20 | b.use :placeholder
21 | b.use :label, wrap_with: { tag: 'div' }
22 | b.wrapper tag: 'div', class: 'controls' do |ba|
23 | ba.use :input
24 | ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
25 | ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
26 | end
27 | end
28 |
29 | config.wrappers :prepend, tag: 'div', class: "control-group", error_class: 'error' do |b|
30 | b.use :html5
31 | b.use :placeholder
32 | b.use :label
33 | b.wrapper tag: 'div', class: 'controls' do |input|
34 | input.wrapper tag: 'div', class: 'input-prepend' do |prepend|
35 | prepend.use :input
36 | end
37 | input.use :hint, wrap_with: { tag: 'span', class: 'help-block' }
38 | input.use :error, wrap_with: { tag: 'span', class: 'help-inline' }
39 | end
40 | end
41 |
42 | config.wrappers :append, tag: 'div', class: "control-group", error_class: 'error' do |b|
43 | b.use :html5
44 | b.use :placeholder
45 | b.use :label
46 | b.wrapper tag: 'div', class: 'controls' do |input|
47 | input.wrapper tag: 'div', class: 'input-append' do |append|
48 | append.use :input
49 | end
50 | input.use :hint, wrap_with: { tag: 'span', class: 'help-block' }
51 | input.use :error, wrap_with: { tag: 'span', class: 'help-inline' }
52 | end
53 | end
54 |
55 | # Wrappers for forms and inputs using the Twitter Bootstrap toolkit.
56 | # Check the Bootstrap docs (http://twitter.github.com/bootstrap)
57 | # to learn about the different styles for forms and inputs,
58 | # buttons and other elements.
59 | config.default_wrapper = :bootstrap
60 | end
61 |
--------------------------------------------------------------------------------
/config/initializers/tagged_logging.rb:
--------------------------------------------------------------------------------
1 | Rails.application.config.log_tags = [ :subdomain, :uuid ]
2 |
--------------------------------------------------------------------------------
/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] if respond_to?(:wrap_parameters)
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
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. Please sign in."
7 | confirmed_and_signed_in: "Your account was successfully confirmed. You are now signed in."
8 | send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes."
9 | 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."
10 | failure:
11 | already_authenticated: "You are already signed in."
12 | inactive: "Your account is not activated yet."
13 | invalid: "Invalid email or password."
14 | invalid_token: "Invalid authentication token."
15 | locked: "Your account is locked."
16 | not_found_in_database: "Invalid email or password."
17 | timeout: "Your session expired. Please sign in again to continue."
18 | unauthenticated: "You need to sign in or sign up before continuing."
19 | unconfirmed: "You have to confirm your account before continuing."
20 | mailer:
21 | confirmation_instructions:
22 | subject: "Confirmation instructions"
23 | reset_password_instructions:
24 | subject: "Reset password instructions"
25 | unlock_instructions:
26 | subject: "Unlock Instructions"
27 | omniauth_callbacks:
28 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
29 | success: "Successfully authenticated from %{kind} account."
30 | passwords:
31 | 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."
32 | send_instructions: "You will receive an email with instructions about how to reset your password in a few minutes."
33 | 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."
34 | updated: "Your password was changed successfully. You are now signed in."
35 | updated_not_active: "Your password was changed successfully."
36 | registrations:
37 | destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon."
38 | signed_up: "Welcome! You have signed up successfully."
39 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
40 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
41 | signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please open the link to activate your account."
42 | 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."
43 | updated: "You updated your account successfully."
44 | sessions:
45 | signed_in: "Signed in successfully."
46 | signed_out: "Signed out successfully."
47 | unlocks:
48 | send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes."
49 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes."
50 | unlocked: "Your account has been unlocked successfully. Please sign in to continue."
51 | errors:
52 | messages:
53 | already_confirmed: "was already confirmed, please try signing in"
54 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
55 | expired: "has expired, please request a new one"
56 | not_found: "not found"
57 | not_locked: "was not locked"
58 | not_saved:
59 | one: "1 error prohibited this %{resource} from being saved:"
60 | other: "%{count} errors prohibited this %{resource} from being saved:"
61 |
--------------------------------------------------------------------------------
/config/locales/en.bootstrap.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 | helpers:
6 | actions: "Actions"
7 | links:
8 | back: "Back"
9 | cancel: "Cancel"
10 | confirm: "Are you sure?"
11 | destroy: "Delete"
12 | new: "New"
13 | edit: "Edit"
14 | titles:
15 | edit: "Edit %{model}"
16 | save: "Save %{model}"
17 | new: "New %{model}"
18 | delete: "Delete %{model}"
19 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
--------------------------------------------------------------------------------
/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 | Wheel::Application.routes.draw do
2 |
3 | devise_for :users, controllers: { registrations: 'registrations' }
4 |
5 | # Authentication
6 | devise_scope :user do
7 | get '/login' => 'devise/sessions#new', as: :login
8 | get '/logout' => 'sessions#destroy', :as => :logout
9 | get '/signup' => 'registrations#new', :as => :signup
10 | scope 'my' do
11 | get 'profile', to: 'registrations#edit'
12 | put 'profile/update', to: 'registrations#update'
13 | get 'password/edit', to: 'registrations#edit_password'
14 | put 'password/update', to: 'registrations#update_password'
15 | end
16 | end
17 |
18 | # The priority is based upon order of creation: first created -> highest priority.
19 | # See how all your routes lay out with 'rake routes'.
20 |
21 | unauthenticated do
22 | get '/logout' => redirect('/')
23 | end
24 |
25 | authenticate :user, ->(u) { u.super_admin? } do
26 | get '/delayed_job' => DelayedJobWeb, :anchor => false
27 | put '/delayed_job' => DelayedJobWeb, :anchor => false
28 | post '/delayed_job' => DelayedJobWeb, :anchor => false
29 |
30 | ActiveAdmin.routes(self)
31 | namespace :superadmin do
32 | root to: 'users#index'
33 | resources :users
34 | end
35 |
36 | end
37 |
38 | get 'pages/about'
39 | get 'pages/contact_us'
40 | get 'pages/redux'
41 | resources :contacts, only: [:create]
42 |
43 | authenticated :user do
44 | get '/pages' => 'pages#index', as: :pages
45 | end
46 |
47 | unauthenticated do
48 | as :user do
49 | root :to => 'devise/sessions#new', as: :unauthenticated_root
50 | end
51 | end
52 |
53 | namespace :api, defaults: { format: :json } do
54 | namespace :v1 do
55 | devise_scope :user do
56 | post 'login' => 'sessions#create', as: 'login'
57 | end
58 |
59 | resources :users, only: [:show, :create, :update, :destroy], constraints: { id: /.*/ }
60 | end
61 | end
62 |
63 | resources :posts do
64 | resources :comments
65 | end
66 |
67 |
68 | root 'posts#index'
69 | end
70 |
--------------------------------------------------------------------------------
/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | default: &default
14 | store_uploaded_assets_in: filesystem
15 | subject_prefix_for_outgoing_emails: WHEEL
16 | mailer_default_from_email: "'Wheel' "
17 | mailer_delivery_method: :smtp
18 | honeybadger_api_key: <%= ENV['HONEYBADGER_API_KEY'] %>
19 |
20 | twilio:
21 | from_number: <%= ENV['TWILIO_FROM_NUMBER'] %>
22 | account_sid: <%= ENV['TWILIO_ACCOUNT_SID'] %>
23 | auth_token: <%= ENV['TWILIO_AUTH_TOKEN'] %>
24 |
25 | aws_s3:
26 | access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
27 | secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
28 | bucket_name: <%= ENV['AWS_S3_BUCKET_NAME'] %>
29 |
30 | support_email: support@wheel.com
31 | host: <%= ENV['APP_URL'] || ENV['HEROKU_URL'] || 'http://localhost:3000' %>
32 |
33 | development:
34 | <<: *default
35 | secret_key_base: 3193ce62de10f78da223e95760dd6c08523cd78204b4d8dc8bb119faf8847adceb70aadce1288ffd8e6232afb3a704c60a75feb024ab937de989322f4e64a385
36 | intercept_and_forward_emails_to:
37 | - john@example.com
38 | - adam@example.com
39 | mailer:
40 | smtp_settings:
41 | user_name: <%= ENV['MANDRILLAPP_USERNAME'] %>
42 | password: <%= ENV['MANDRILLAPP_PASSWORD'] %>
43 | address: smtp.mandrillapp.com
44 | port: 587
45 | authentication: plain
46 | devise:
47 | secret_key: c0cd8c380935936ff6c6bfb7b0f0ed3f3a2d66d7d7b445394a879dea71bfb5711799c7840e7d4fd93fe8a0983c4f27fd30caebea879dff734c15ff1696262144
48 |
49 | test:
50 | <<: *default
51 | secret_key_base: 08523cd7820d8e6232afb3a704c60a75feb024ab937de989322f4e64a3854b4d8dc8bb119faf8847adceb70aadce1288ff3193ce62de10f78da223e95760dd6c
52 | mailer_delivery_method: :test
53 | mailer:
54 | smtp_settings:
55 | user_name: <%= ENV['MANDRILLAPP_USERNAME'] %>
56 | password: <%= ENV['MANDRILLAPP_PASSWORD'] %>
57 | address: smtp.mandrillapp.com
58 | port: 587
59 | authentication: plain
60 | devise:
61 | secret_key: 5394a879dea71bfbc0cd8c380935936ff6c6b5711799c7840e7d4fd93fe8a0983c4f27fd30caebea879dff734c15ff1696262144fb7b0f0ed3f3a2d66d7d7b44
62 |
63 | staging:
64 | <<: *default
65 | store_uploaded_assets_in: aws_s3
66 | secret_key_base: b731f261415e6f13e3e3e5a6726ee163707938f38514331fc2a67eda3800dd428bfe2a0c3b4ed83cf99e7df643e93b450511f81e05556712128ae786559ada6e
67 | mailer:
68 | smtp_settings:
69 | user_name: <%= ENV['MANDRILLAPP_USERNAME'] %>
70 | password: <%= ENV['MANDRILLAPP_PASSWORD'] %>
71 | domain: www.wheel.com
72 | address: smtp.mandrillapp.com
73 | port: 587
74 | authentication: plain
75 | enable_starttls_auto: true
76 |
77 | intercept_and_forward_emails_to:
78 | - john@example.com
79 | - adam@example.com
80 | devise:
81 | secret_key: ecd10b29124e0b3c68890e6c019566fc8a4b3f3bc519eb99d3d06d05f0a7ce3df1522472eb90e1ffc56b03119a9ed5e3e6e412bca67003c2ee449715fd98b94c
82 |
83 | production:
84 | <<: *default
85 | store_uploaded_assets_in: aws_s3
86 | secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
87 | mailer:
88 | smtp_settings:
89 | user_name: <%= ENV['MANDRILLAPP_USERNAME'] %>
90 | password: <%= ENV['MANDRILLAPP_PASSWORD'] %>
91 | domain: www.wheel.com
92 | address: smtp.mandrillapp.com
93 | port: 587
94 | authentication: plain
95 | enable_starttls_auto: true
96 |
97 | devise:
98 | secret_key: <%= ENV['DEVISE_KEY'] %>
99 |
--------------------------------------------------------------------------------
/config/unicorn.rb:
--------------------------------------------------------------------------------
1 | # this template has been picked up from
2 | # https://devcenter.heroku.com/articles/rails-unicorn
3 |
4 | worker_processes Integer(ENV["WEB_CONCURRENCY"] || 2)
5 |
6 | # 30 seconds is the timeout for heroku. If it is not
7 | # deployed on heroku then it can be bumped up.
8 | timeout 30
9 |
10 | preload_app true
11 |
12 | before_fork do |server, worker|
13 | Signal.trap 'TERM' do
14 | puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
15 | Process.kill 'QUIT', Process.pid
16 | end
17 |
18 | defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
19 | end
20 |
21 | after_fork do |server, worker|
22 | Signal.trap 'TERM' do
23 | puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
24 | end
25 |
26 | defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
27 | end
28 |
--------------------------------------------------------------------------------
/db/migrate/20131112184628_add_devise_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddDeviseToUsers < ActiveRecord::Migration
2 | def self.up
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, :null => false
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 | t.timestamps
23 | end
24 |
25 | add_index :users, :email, :unique => true
26 | add_index :users, :reset_password_token, :unique => true
27 | # add_index :users, :confirmation_token, :unique => true
28 | # add_index :users, :unlock_token, :unique => true
29 | end
30 |
31 | def self.down
32 | drop_table :users
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/db/migrate/20131120170220_create_delayed_jobs.rb:
--------------------------------------------------------------------------------
1 | class CreateDelayedJobs < ActiveRecord::Migration
2 | def self.up
3 | create_table :delayed_jobs, :force => true do |table|
4 | table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
5 | table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
6 | table.text :handler # YAML-encoded string of the object that will do work
7 | table.text :last_error # reason for last failure (See Note below)
8 | table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
9 | table.datetime :locked_at # Set when a client is working on this object
10 | table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
11 | table.string :locked_by # Who is working on this object (if locked)
12 | table.string :queue # The name of the queue this job is in
13 | table.timestamps
14 | end
15 |
16 | add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
17 | end
18 |
19 | def self.down
20 | drop_table :delayed_jobs
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/db/migrate/20131122045009_add_user_attributes.rb:
--------------------------------------------------------------------------------
1 | class AddUserAttributes < ActiveRecord::Migration
2 | def change
3 | add_column :users, :last_name, :string
4 | add_column :users, :first_name, :string
5 | add_column :users, :role, :string, default: 'standard'
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20131213184726_create_active_admin_comments.rb:
--------------------------------------------------------------------------------
1 | class CreateActiveAdminComments < ActiveRecord::Migration
2 | def self.up
3 | create_table :active_admin_comments do |t|
4 | t.string :namespace
5 | t.text :body
6 | t.string :resource_id, :null => false
7 | t.string :resource_type, :null => false
8 | t.references :author, :polymorphic => true
9 | t.timestamps
10 | end
11 | add_index :active_admin_comments, [:namespace]
12 | add_index :active_admin_comments, [:author_type, :author_id]
13 | add_index :active_admin_comments, [:resource_type, :resource_id]
14 | end
15 |
16 | def self.down
17 | drop_table :active_admin_comments
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/db/migrate/20140220111712_add_authentication_token_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddAuthenticationTokenToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :authentication_token, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140225143027_add_profile_image_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddProfileImageToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :profile_image, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20150827192424_create_posts.rb:
--------------------------------------------------------------------------------
1 | class CreatePosts < ActiveRecord::Migration
2 | def change
3 | create_table :posts do |t|
4 | t.string :title
5 | t.text :content
6 | t.belongs_to :user, index: true
7 |
8 | t.timestamps null: false
9 | end
10 |
11 | add_foreign_key :posts, :users, on_delete: :cascade
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20150827192538_create_comments.rb:
--------------------------------------------------------------------------------
1 | class CreateComments < ActiveRecord::Migration
2 | def change
3 | create_table :comments do |t|
4 | t.text :content
5 | t.belongs_to :user, index: true
6 | t.belongs_to :post, index: true
7 |
8 | t.timestamps null: false
9 | end
10 |
11 | add_foreign_key :comments, :users, on_delete: :cascade
12 | add_foreign_key :comments, :posts, on_delete: :cascade
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/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 that you check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(version: 20150827192538) do
15 |
16 | create_table "active_admin_comments", force: :cascade do |t|
17 | t.string "namespace"
18 | t.text "body"
19 | t.string "resource_id", null: false
20 | t.string "resource_type", null: false
21 | t.integer "author_id"
22 | t.string "author_type"
23 | t.datetime "created_at"
24 | t.datetime "updated_at"
25 | end
26 |
27 | add_index "active_admin_comments", ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id"
28 | add_index "active_admin_comments", ["namespace"], name: "index_active_admin_comments_on_namespace"
29 | add_index "active_admin_comments", ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id"
30 |
31 | create_table "comments", force: :cascade do |t|
32 | t.text "content"
33 | t.integer "user_id"
34 | t.integer "post_id"
35 | t.datetime "created_at", null: false
36 | t.datetime "updated_at", null: false
37 | end
38 |
39 | add_index "comments", ["post_id"], name: "index_comments_on_post_id"
40 | add_index "comments", ["user_id"], name: "index_comments_on_user_id"
41 |
42 | create_table "delayed_jobs", force: :cascade do |t|
43 | t.integer "priority", default: 0
44 | t.integer "attempts", default: 0
45 | t.text "handler"
46 | t.text "last_error"
47 | t.datetime "run_at"
48 | t.datetime "locked_at"
49 | t.datetime "failed_at"
50 | t.string "locked_by"
51 | t.string "queue"
52 | t.datetime "created_at"
53 | t.datetime "updated_at"
54 | end
55 |
56 | add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority"
57 |
58 | create_table "posts", force: :cascade do |t|
59 | t.string "title"
60 | t.text "content"
61 | t.integer "user_id"
62 | t.datetime "created_at", null: false
63 | t.datetime "updated_at", null: false
64 | end
65 |
66 | add_index "posts", ["user_id"], name: "index_posts_on_user_id"
67 |
68 | create_table "users", force: :cascade do |t|
69 | t.string "email", default: "", null: false
70 | t.string "encrypted_password", default: "", null: false
71 | t.string "reset_password_token"
72 | t.datetime "reset_password_sent_at"
73 | t.datetime "remember_created_at"
74 | t.integer "sign_in_count", default: 0, null: false
75 | t.datetime "current_sign_in_at"
76 | t.datetime "last_sign_in_at"
77 | t.string "current_sign_in_ip"
78 | t.string "last_sign_in_ip"
79 | t.datetime "created_at"
80 | t.datetime "updated_at"
81 | t.string "last_name"
82 | t.string "first_name"
83 | t.string "role", default: "standard"
84 | t.string "authentication_token"
85 | t.string "profile_image"
86 | end
87 |
88 | add_index "users", ["email"], name: "index_users_on_email", unique: true
89 | add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
90 |
91 | end
92 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/doc/api.md:
--------------------------------------------------------------------------------
1 | ### Testing with api using curl
2 |
3 | ``` ruby
4 | user = User.where(email: 'john@example.com').first
5 | auth_token = user.authentication_token
6 | ```
7 |
8 | In the following example replace the `auth_token` value with the value derived in the above step when appropriate.
9 |
10 | ### Show user information
11 |
12 | ```
13 | curl -v \
14 | -H "X-Auth-Token: pFfxLhBgvnoYeXnbDnFL" \
15 | -H "Accept: application/json" \
16 | -H "Content-type: application/json" \
17 | http://localhost:3000/api/v1/users/john@example.com
18 | ```
19 |
20 | ### Update user information
21 |
22 | Using `wrap_parameters` .
23 |
24 | ```
25 | curl -v \
26 | -X PUT \
27 | -H "X-Auth-Token: pFfxLhBgvnoYeXnbDnFL" \
28 | -H "Accept: application/json" \
29 | -H "Content-type: application/json" \
30 | -d '{"first_name":"Johnny"}' \
31 | http://localhost:3000/api/v1/users/john@example.com
32 | ```
33 |
34 | Without using `wrap_parameters` .
35 |
36 | ```
37 | curl -v \
38 | -X PUT \
39 | -H "X-Auth-Token: pFfxLhBgvnoYeXnbDnFL" \
40 | -H "Accept: application/json" \
41 | -H "Content-type: application/json" \
42 | -d '{"user":{"first_name":"Johnny"}}' \
43 | http://localhost:3000/api/v1/users/john@example.com
44 | ```
45 |
46 | #### Deleting a user
47 |
48 | ```
49 | curl -v \
50 | -X DELETE \
51 | -H "X-Auth-Token: jz_sPhqn-8jySr_72Ehj" \
52 | -H "Accept: application/json" \
53 | -H "Content-type: application/json" \
54 | http://localhost:3000/api/v1/users/john@example.com
55 | ```
56 |
57 | #### Adding a new user
58 |
59 | ```
60 | curl -v \
61 | -X POST \
62 | -H "Accept: application/json" \
63 | -H "Content-type: application/json" \
64 | -d '{"first_name":"Mary","last_name":"Smith","email":"mary@example.com","[user]password":"welcome","password_confirmation":"welcome"}' \
65 | http://localhost:3000/api/v1/users
66 | ```
67 |
--------------------------------------------------------------------------------
/doc/why_database_name_only_63_characters_long.md:
--------------------------------------------------------------------------------
1 | ### Why length of table name is limited to 63 characters long?
2 |
3 | The default limit on length of identifiers in PostGreSQL is 63 because
4 | value of `NAMEDATALEN` constant is 64 by default. The length of identifiers
5 | is `NAMEDATALEN - 1` which becomes `64 - 1` equal to 63.
6 |
7 | This configuration can't be changed without compiling PostGreSQL again.
8 | We use name of the repository and name of branch to dynamically
9 | calculate database name for every branch. But if the length of this
10 | combination becomes greater than 63 then it gives error:
11 |
12 | ```
13 | Input string is longer than NAMEDATALEN-1 (63)
14 | ```
15 |
16 | To avoid this, we have restricted the length of the database name to
17 | maximum 63 characters. This has a possible side-effect that 2 branches with long names and
18 | similar characters upto length 63 will have same database name. But
19 | it is very unlikely.
20 |
--------------------------------------------------------------------------------
/lib/tasks/setup.rake:
--------------------------------------------------------------------------------
1 | desc 'Ensure that code is not running in production environment'
2 | task :not_production do
3 | raise 'do not run in production' if Rails.env.production?
4 | end
5 |
6 | desc 'Sets up the project by running migration and populating sample data'
7 | task setup: [:environment, :not_production, 'db:drop', 'db:create', 'db:migrate'] do
8 | ["setup_sample_data"].each { |cmd| system "rake #{cmd}" }
9 | end
10 |
11 | def delete_all_records_from_all_tables
12 | ActiveRecord::Base.connection.schema_cache.clear!
13 |
14 | Dir.glob(Rails.root + 'app/models/*.rb').each { |file| require file }
15 |
16 | ActiveRecord::Base.descendants.each do |klass|
17 | klass.reset_column_information
18 | klass.delete_all
19 | end
20 | end
21 |
22 | desc 'Deletes all records and populates sample data'
23 | task setup_sample_data: [:environment, :not_production] do
24 | delete_all_records_from_all_tables
25 |
26 | create_user email: 'sam@example.com'
27 |
28 | puts 'sample data was added successfully'
29 | end
30 |
31 | def create_user( options = {} )
32 | user_attributes = { email: 'sam@example.com',
33 | password: 'welcome',
34 | first_name: "Sam",
35 | last_name: "Smith",
36 | role: "super_admin" }
37 | attributes = user_attributes.merge options
38 | User.create! attributes
39 | end
40 |
41 |
--------------------------------------------------------------------------------
/lib/templates/erb/scaffold/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%%= simple_form_for(@<%= singular_table_name %>) do |f| %>
2 | <%%= f.error_notification %>
3 |
4 |
5 | <%- attributes.each do |attribute| -%>
6 | <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %>
7 | <%- end -%>
8 |
9 |
10 |
11 | <%%= f.button :submit %>
12 |
13 | <%% end %>
14 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
48 |
49 |
50 |
51 |
52 |
53 |
The page you were looking for doesn't exist.
54 |
You may have mistyped the address or the page may have moved.
55 |
56 | If you are the application owner check the logs for more information.
57 |
58 |
59 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
48 |
49 |
50 |
51 |
52 |
53 |
The change you wanted was rejected.
54 |
Maybe you tried to change something you didn't have access to.
55 |
56 | If you are the application owner check the logs for more information.
57 |
58 |
59 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
48 |
49 |
50 |
51 |
52 |
53 |
We're sorry, but something went wrong.
54 |
55 | If you are the application owner check the logs for more information.
56 |
57 |
58 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vipulnsward/react-rails-examples/a8fdfc190d6ffbddfe11c9e9c7574345ad8ad9c8/public/favicon.ico
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/test/controllers/active_admin/dashboard_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ActiveAdmin::DashboardControllerTest < ActionController::TestCase
4 | fixtures :all
5 |
6 | def setup
7 | sign_in users(:admin)
8 | end
9 |
10 | def test_index_success_for_super_admin
11 | get :index
12 | assert_response :success
13 | end
14 |
15 | def test_index_redirects_for_non_super_admin
16 | sign_in users(:nancy)
17 | get :index
18 | assert_response :forbidden
19 | end
20 |
21 | end
22 |
--------------------------------------------------------------------------------
/test/controllers/api/v1/sessions_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Api::V1::SessionsControllerTest < ActionController::TestCase
4 |
5 | def test_valid_email_and_password_should_be_able_to_log_in
6 | admin = users :admin
7 | post :create, user: { email: admin.email, password: 'welcome' }
8 | assert_response :success
9 | end
10 |
11 | def test_wrong_combination_of_email_and_password_should_not_be_able_to_log_in
12 | non_existent_email = 'this_email_does_not_exist_in_db@example.email'
13 | post :create, user: { email: non_existent_email, password: 'welcome' }
14 | assert_response 401
15 | assert_equal 'Incorrect email or password', JSON.parse(response.body)['error']
16 | end
17 |
18 | def test_should_return_auth_token
19 | admin = users :admin
20 |
21 | post :create, user: { email: admin.email, password: 'welcome' }
22 |
23 | assert_response :success
24 | assert JSON.parse(response.body)['auth_token']
25 | end
26 |
27 | end
28 |
--------------------------------------------------------------------------------
/test/controllers/api/v1/users_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Api::V1::UsersControllerTest < ActionController::TestCase
4 |
5 | def test_show_for_a_valid_user
6 | admin = users(:admin)
7 | set_auth_headers!(admin)
8 |
9 | get :show, { id: admin.email, format: :json }
10 |
11 | assert_response :success
12 | json = JSON.parse(response.body)
13 | assert_equal %w{ email first_name last_name current_sign_in_at }.sort, json.keys.sort
14 | end
15 |
16 | def test_show_when_email_is_not_present
17 | admin = users :admin
18 | an_invalid_email = 'this_email_is_not_present_in_db@example.com'
19 | set_auth_headers!(admin)
20 |
21 | get :show, { id: an_invalid_email, format: :json }
22 |
23 | assert_response 401
24 | assert_equal "Could not authenticate with the provided credentials", JSON.parse(response.body)['error']
25 | end
26 |
27 | def test_create_user_with_valid_info
28 | valid_email = 'john@example.com'
29 |
30 | valid_user_json = { email: valid_email,
31 | first_name: 'John',
32 | last_name: 'Smith',
33 | password: 'welcome',
34 | password_confirmation: 'welcome',
35 | phone_number: '1(555)555-5555' }
36 |
37 | # Ensure that there are no users with this email in db
38 | User.delete_all(email: valid_email)
39 |
40 | assert_difference 'User.count', 1 do
41 | post :create, user: valid_user_json
42 | assert_response :success
43 | end
44 | end
45 |
46 | def test_create_user_should_return_error_for_invalid_data
47 | valid_email = 'john@example.com'
48 |
49 | invalid_user_json = { email: valid_email,
50 | first_name: 'John',
51 | last_name: 'Smith',
52 | password: nil # Invalid password
53 | }
54 |
55 | # Ensure that there are no users with this email in db
56 | User.delete_all( email: valid_email )
57 |
58 | post :create, user: invalid_user_json
59 | assert_response 422
60 | assert_equal "Password can't be blank", JSON.parse(response.body)['error']
61 | end
62 |
63 | def test_update_should_not_succeed_without_authentication
64 | admin = users :admin
65 | json_data = admin.as_json
66 | put :update, { id: admin.email, user: json_data }
67 | assert_response 401
68 | end
69 |
70 | def test_update_should_return_error_when_email_is_not_present
71 | admin = users(:admin)
72 | an_invalid_email = 'this_email_is_not_present_in_db@example.com'
73 | set_auth_headers!(admin)
74 |
75 | put :update, { id: an_invalid_email, format: :json }
76 |
77 | assert_response 401
78 | assert_equal "Could not authenticate with the provided credentials", JSON.parse(response.body)['error']
79 | end
80 |
81 | def test_update_user_should_succeed_for_valid_data
82 | admin = users(:admin)
83 | new_first_name = 'John2'
84 | set_auth_headers!(admin)
85 |
86 | put :update, { id: admin.email, user: { first_name: new_first_name }, format: :json }
87 |
88 | assert_response :success
89 | admin.reload
90 | assert_equal new_first_name, admin.first_name
91 | end
92 |
93 | def test_update_user_should_return_error_for_invalid_data
94 | admin = users(:admin)
95 |
96 | set_auth_headers!(admin)
97 |
98 | put :update, { id: admin.email, format: :json, user: { password: 'new test password', password_confirmation: 'not matching confirmation' } }
99 | assert_response 422
100 |
101 | assert_equal "Password confirmation doesn't match Password", JSON.parse(response.body)['error'], response.body
102 | end
103 |
104 | def test_destroy_should_not_be_invokable_without_authentication
105 | admin = users :admin
106 | delete :destroy, id: admin.email
107 | assert_response 401
108 |
109 | assert_equal 'Could not authenticate with the provided credentials', JSON.parse(response.body)['error']
110 | end
111 |
112 | def test_destroy_should_destroy_user
113 | admin = users :admin
114 | set_auth_headers!(admin)
115 |
116 | assert_difference 'User.count', -1 do
117 | delete :destroy, { id: admin.email, format: :json }
118 | assert_response :success
119 | end
120 | end
121 |
122 | def test_destroy_should_return_error_if_email_is_not_present_in_database
123 | admin = users :admin
124 | email = 'this_email_is_not_present_in_db@example.com'
125 |
126 | set_auth_headers!(admin)
127 |
128 | delete :destroy, { id: email, format: :json }
129 |
130 | assert_response 401
131 | assert_equal "Could not authenticate with the provided credentials", JSON.parse(response.body)['error']
132 | end
133 |
134 | def set_auth_headers!(user)
135 | request.headers['X-Auth-Token'] = user.authentication_token
136 | end
137 |
138 | end
139 |
--------------------------------------------------------------------------------
/test/controllers/contacts_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ContactsControllerTest < ActionController::TestCase
4 |
5 | def setup
6 | request.env["HTTP_REFERER"] = "http://test.com"
7 | end
8 |
9 | def test_create_success
10 | contact_param = { contact: { title: 'contact title',
11 | body: 'some message',
12 | email: 'bob@example.com' } }
13 | post :create, contact_param
14 |
15 | assert_includes ActionMailer::Base.deliveries.last.from, contact_param[:contact][:email]
16 | assert_redirected_to pages_contact_us_path
17 | assert_equal 'Thank you for your message. We will contact you soon!', flash[:notice]
18 | end
19 |
20 | def test_create_failure
21 | post :create, contact: { title: 'contact title',
22 | body: 'some message',
23 | email: 'bob' }
24 |
25 | contact = assigns :contact
26 | assert_includes contact.errors.full_messages, 'Email is invalid'
27 | end
28 |
29 | def test_create_failure_should_render_contact_us_template
30 | post :create, contact: { title: 'contact title',
31 | body: 'some message',
32 | email: 'bob' }
33 |
34 | assert_template "pages/contact_us"
35 | assert_not_nil assigns(:contact)
36 | end
37 |
38 | end
39 |
--------------------------------------------------------------------------------
/test/controllers/home_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class HomeControllerTest < ActionController::TestCase
4 |
5 | def test_index_renders_message
6 | admin = users :admin
7 | sign_in admin
8 |
9 | get :index
10 |
11 | assert_response :success
12 | end
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/test/controllers/pages_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class PagesControllerTest < ActionController::TestCase
4 |
5 | def test_index_success
6 | get :index
7 |
8 | assert_response :success
9 | end
10 |
11 | def test_contact_us_success
12 | get :contact_us
13 |
14 | assert_response :success
15 | end
16 |
17 | def test_about_success
18 | get :about
19 |
20 | assert_response :success
21 | end
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/test/controllers/registrations_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class RegistrationsControllerTest < ActionController::TestCase
4 |
5 | setup do
6 | request.env['devise.mapping'] = Devise.mappings[:user]
7 | end
8 |
9 | def test_successfull_user_registration
10 | assert_difference('User.count') do
11 | post :create, { user: { email: "nancy@test.example.com",
12 | first_name: "Nancy",
13 | last_name: "Smith",
14 | password: "welcome",
15 | phone_number: '1(555)555-5555',
16 | password_confirmation: "welcome" } }
17 | end
18 | assert_redirected_to root_path
19 | end
20 |
21 | def test_required_parameters
22 | assert_no_difference('User.count') do
23 | post :create, {user: {email: "steve@example.com", password: "welcome", password_confirmation: "welcome"}}
24 | end
25 |
26 | assert_response :success
27 | end
28 |
29 | def test_updates_password_given_valid_data
30 | nancy = users :nancy
31 | sign_in nancy
32 |
33 | get :edit_password
34 | assert_response :success
35 |
36 | valid_user_data = { password: 'new password', password_confirmation: 'new password', current_password: 'welcome' }
37 | put :update_password, user: valid_user_data
38 | assert_redirected_to root_path
39 | end
40 |
41 | def test_does_not_update_password_given_invalid_data
42 | nancy = users :nancy
43 | sign_in nancy
44 |
45 | get :edit_password
46 | assert_response :success
47 |
48 | invalid_user_data = { password: 'new password', password_confirmation: 'new not matching password', current_password: 'welcome' }
49 |
50 | put :update_password, user: invalid_user_data
51 | assert_response :success
52 | assert assigns(:user)
53 | @user = assigns(:user)
54 | assert @user.errors.count > 0
55 | end
56 |
57 | def test_updates_user_profile_given_valid_data
58 | nancy = users :nancy
59 | sign_in nancy
60 |
61 | get :edit
62 | assert_response :success
63 |
64 | valid_user_data = { first_name: 'John2', current_password: 'welcome' }
65 | put :update, user: valid_user_data
66 | assert_redirected_to root_path
67 | nancy.reload
68 | assert_equal nancy.first_name, valid_user_data[:first_name]
69 | end
70 |
71 | end
72 |
--------------------------------------------------------------------------------
/test/controllers/superadmin/users_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Superadmin::UsersControllerTest < ActionController::TestCase
4 |
5 | def test_index_when_user_is_superadmin
6 | user = users :admin
7 | sign_in user
8 | get :index
9 | assert_response :success
10 | end
11 |
12 | def test_index_when_user_is_not_superadmin
13 | user = users :nancy
14 | sign_in user
15 | get :index
16 | assert_response :forbidden
17 | end
18 |
19 | def test_edit_user_modal_success_response
20 | user = users :admin
21 | sign_in user
22 | get :edit, id: users(:nancy)
23 | assert_response :success
24 | end
25 |
26 | def test_user_update_success
27 | admin = users :admin
28 | sign_in admin
29 | nancy = users :nancy
30 |
31 | post :update, id: nancy, user: {first_name: 'Jane'}
32 | nancy.reload
33 |
34 | assert 'Jane', nancy.first_name
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/test/fixtures/comments.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | one:
4 | content: MyText
5 | user_id:
6 | post_id:
7 |
8 | two:
9 | content: MyText
10 | user_id:
11 | post_id:
12 |
--------------------------------------------------------------------------------
/test/fixtures/posts.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | one:
4 | title: MyString
5 | content: MyText
6 | user_id:
7 |
8 | two:
9 | title: MyString
10 | content: MyText
11 | user_id:
12 |
--------------------------------------------------------------------------------
/test/fixtures/users.yml:
--------------------------------------------------------------------------------
1 | admin:
2 | email: 'admin@example.com'
3 | first_name: 'Adam'
4 | last_name: 'Smith'
5 | encrypted_password: '$2a$10$3OF9YyLG6D8P8EqFFdudmeIUtIlnX2usIFYhAJ77pep5y93BLuSuu' #welcome
6 | reset_password_token: 5h632xrnASqFanDhKQsB8
7 | role: 'super_admin'
8 | authentication_token: 5h632xrnASqFanDhKQsB8
9 |
10 | nancy:
11 | email: nancy.smith@example.com
12 | first_name: 'Nancy'
13 | last_name: 'Smith'
14 | encrypted_password: '$2a$10$3OF9YyLG6D8P8EqFFdudmeIUtIlnX2usIFYhAJ77pep5y93BLuSuu' #welcome
15 | reset_password_token: 5h632xrnASsFanDhKQsB7
16 | authentication_token: 5h632xrnASqFanDhKQsB8
17 |
--------------------------------------------------------------------------------
/test/integration/api_invalid_json_data_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ApiInvalidJsonDataTest < ActionDispatch::IntegrationTest
4 |
5 | def test_invalid_payload_responds_with_message
6 | invalid_json = %Q{ { "foo":'bar' } }
7 |
8 | post "/v1/users", invalid_json , "CONTENT_TYPE" => 'application/json'
9 |
10 | assert_response 400
11 | assert response.body.include?("Payload data is not valid JSON"), response.body
12 | end
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/test/integration/compression_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class CompressionTest < ActionDispatch::IntegrationTest
4 | def test_a_visitor_browser_that_supports_compression
5 | ['deflate','gzip', 'deflate,gzip','gzip,deflate'].each do|compression_method|
6 | get root_path, {}, {'HTTP_ACCEPT_ENCODING' => compression_method }
7 | assert response.headers['Content-Encoding']
8 | end
9 | end
10 |
11 | def test_a_visitor_browser_does_not_support_compression
12 | get root_path
13 | assert_not response.headers['Content-Encoding']
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/test/models/comment_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class CommentTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/contact_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ContactTest < ActiveSupport::TestCase
4 |
5 | def test_valid_contact
6 | valid_contact = { email: 'bob@exmaple.com',
7 | title: 'need help',
8 | body: 'some message' }
9 |
10 | contact = Contact.new(valid_contact)
11 |
12 | assert contact.valid?
13 | end
14 |
15 | def test_invalid_contact
16 | invalid_contact = { email: 'bob',
17 | title: '',
18 | body: 'some message' }
19 |
20 | contact = Contact.new(invalid_contact)
21 |
22 | assert_not contact.valid?
23 | assert_includes contact.errors.full_messages, "Title can't be blank"
24 | assert_includes contact.errors.full_messages, "Email is invalid"
25 | end
26 |
27 | end
28 |
--------------------------------------------------------------------------------
/test/models/post_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class PostTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/user_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UserTest < ActiveSupport::TestCase
4 |
5 | def test_admin_is_indeed_super_admin
6 | user = users :admin
7 | assert user.super_admin?
8 | end
9 |
10 | def test_first_name_is_blank
11 | user = users :admin
12 | user.first_name = nil
13 | assert_equal 'Smith', user.name
14 | end
15 |
16 | def test_last_name_is_blank
17 | user = users :admin
18 | user.last_name = nil
19 | assert_equal 'Adam', user.name
20 | end
21 |
22 | def test_as_json
23 | user = users :admin
24 |
25 | expected = {"email"=>"admin@example.com", "current_sign_in_at"=>nil, "last_name"=>"Smith", "first_name"=>"Adam"}
26 | assert_equal expected, user.as_json
27 | end
28 |
29 | end
30 |
--------------------------------------------------------------------------------
/test/services/addition_service_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class AdditonServiceTest < ActiveSupport::TestCase
4 |
5 | def test_addition
6 | service = AdditionService.new 5, 10
7 | assert_equal 15, service.process
8 | end
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 |
2 | def enable_test_coverage
3 | require 'simplecov'
4 |
5 | SimpleCov.start do
6 | add_filter '/test/'
7 |
8 | add_group 'Models', 'app/models'
9 | add_group 'Mailers', 'app/mailers'
10 | add_group 'Controllers', 'app/controllers'
11 | add_group 'Uploaders', 'app/uploaders'
12 | add_group 'Helpers', 'app/helpers'
13 | add_group 'Workers', 'app/workers'
14 | add_group 'Services', 'app/services'
15 | end
16 | end
17 |
18 | enable_test_coverage if ENV['COVERAGE']
19 |
20 | ENV["RAILS_ENV"] ||= "test"
21 |
22 | require File.expand_path('../../config/environment', __FILE__)
23 | require 'rails/test_help'
24 |
25 | if Rails.application.config.colorize_logging
26 | require 'minitest/reporters'
27 | require 'minitest/pride'
28 |
29 | # Refer https://github.com/kern/minitest-reporters#caveats
30 | # If you want to see full stacktrace then just use
31 | # MiniTest::Reporters.use!
32 |
33 | MiniTest::Reporters.use! Minitest::Reporters::ProgressReporter.new,
34 | ENV,
35 | Minitest.backtrace_filter
36 | end
37 |
38 | class ActiveSupport::TestCase
39 |
40 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
41 | #
42 | # Note: You'll currently still have to declare fixtures explicitly in integration tests
43 | # -- they do not yet inherit this setting
44 | fixtures :all
45 |
46 | # Add more helper methods to be used by all tests here...
47 | end
48 |
49 | class ActionController::TestCase
50 | include Devise::TestHelpers
51 | end
52 |
--------------------------------------------------------------------------------