├── .codeclimate.yml ├── .gitignore ├── .rspec ├── .rubocop.yml ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── app ├── channels │ └── application_cable │ │ ├── channel.rb │ │ └── connection.rb ├── controllers │ ├── application_controller.rb │ ├── concerns │ │ └── .keep │ ├── public_controller.rb │ └── todos_controller.rb ├── jobs │ └── application_job.rb ├── mailers │ └── application_mailer.rb ├── models │ ├── ability.rb │ ├── application_record.rb │ ├── concerns │ │ └── .keep │ ├── todo.rb │ └── user.rb └── views │ ├── layouts │ ├── mailer.html.erb │ └── mailer.text.erb │ ├── public │ └── index.json.jbuilder │ └── todos │ ├── index.json.jbuilder │ └── show.json.jbuilder ├── bin ├── bundle ├── rails ├── rake ├── setup ├── spring └── update ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── active_record_belongs_to_required_by_default.rb │ ├── application_controller_renderer.rb │ ├── backtrace_silencers.rb │ ├── callback_terminator.rb │ ├── cors.rb │ ├── devise.rb │ ├── devise_token_auth.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── rack_attack.rb │ ├── rack_timeout.rb │ ├── readthis.rb │ ├── sidekiq.rb │ ├── ssl_options.rb │ ├── to_time_preserves_timezone.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ └── en.yml ├── puma.rb ├── redis.conf ├── routes.rb ├── secrets.yml ├── sidekiq.yml └── spring.rb ├── coverage ├── .last_run.json ├── .resultset.json ├── .resultset.json.lock ├── assets │ └── 0.10.0 │ │ ├── application.css │ │ ├── application.js │ │ ├── colorbox │ │ ├── border.png │ │ ├── controls.png │ │ ├── loading.gif │ │ └── loading_background.png │ │ ├── favicon_green.png │ │ ├── favicon_red.png │ │ ├── favicon_yellow.png │ │ ├── loading.gif │ │ ├── magnify.png │ │ └── smoothness │ │ └── images │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png │ │ ├── ui-icons_222222_256x240.png │ │ ├── ui-icons_2e83ff_256x240.png │ │ ├── ui-icons_454545_256x240.png │ │ ├── ui-icons_888888_256x240.png │ │ └── ui-icons_cd0a0a_256x240.png └── index.html ├── db ├── migrate │ ├── 20160515174916_create_todos.rb │ └── 20160517090314_devise_token_auth_create_users.rb ├── schema.rb └── seeds.rb ├── doc ├── api.raml └── schemas │ └── auth │ └── post.request.json ├── docker-compose.yml ├── lib └── tasks │ ├── .keep │ └── docs_generate.rake ├── log └── .keep ├── public ├── 404.html ├── 422.html ├── 500.html ├── apple-touch-icon-precomposed.png ├── apple-touch-icon.png ├── favicon.ico └── robots.txt ├── spec ├── acceptance │ ├── auth_spec.rb │ └── todos_spec.rb ├── controllers │ └── todos_controller_spec.rb ├── factories │ ├── todos.rb │ └── user.rb ├── models │ └── todo_spec.rb ├── rails_helper.rb ├── routing │ └── todos_routing_spec.rb ├── spec_helper.rb └── support │ └── settings │ └── rspec_api_documentation.rb └── tmp └── .keep /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | brakeman: 4 | enabled: true 5 | bundler-audit: 6 | enabled: true 7 | duplication: 8 | enabled: true 9 | config: 10 | languages: 11 | - ruby 12 | fixme: 13 | enabled: true 14 | rubocop: 15 | enabled: true 16 | ratings: 17 | paths: 18 | - Gemfile.lock 19 | - "**.erb" 20 | - "**.haml" 21 | - "**.rb" 22 | - "**.module" 23 | exclude_paths: 24 | - config/ 25 | - db/ 26 | - spec/ 27 | - coverage/ 28 | - .idea 29 | - .git -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-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 all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | # Ignore Byebug command history file. 21 | .byebug_history 22 | 23 | # Rubymine 24 | /.idea 25 | 26 | # Documentation 27 | /doc/spec_documentation/* 28 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.3.1 2 | 3 | RUN apt-get update -qq && apt-get install -y build-essential 4 | 5 | ENV APP_HOME /app 6 | RUN mkdir $APP_HOME 7 | WORKDIR $APP_HOME 8 | 9 | ADD Gemfile* $APP_HOME/ 10 | 11 | ENV BUNDLE_GEMFILE=$APP_HOME/Gemfile \ 12 | BUNDLE_JOBS=2 \ 13 | BUNDLE_PATH=/bundle 14 | 15 | RUN bundle install --retry 3 16 | 17 | ADD . $APP_HOME 18 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Rails 4 | gem 'rails', '5.0.0' 5 | 6 | # Use sqlite3 as the database for Active Record 7 | gem 'sqlite3' 8 | gem 'pg' 9 | 10 | # Use Puma as the app server 11 | gem 'puma', '~> 3.0' 12 | 13 | # Security, limit number request per second. Read more: https://github.com/kickstarter/rack-attack 14 | gem 'rack-attack' 15 | 16 | # Build JSON APIs with ease. 17 | # Read more: https://github.com/rails/jbuilder 18 | gem 'jbuilder', :git => 'git://github.com/diwaniuk/jbuilder.git' 19 | 20 | # Faster rendering JSON file. 21 | # Read more: https://github.com/brianmario/yajl-ruby 22 | gem 'yajl-ruby', require: 'yajl' 23 | 24 | # Schema validation 25 | # https://github.com/ruby-json-schema/json-schema 26 | gem 'json-schema' 27 | 28 | # Timeout for long-running request 29 | gem 'rack-timeout' 30 | 31 | # Token based authentication for Rails JSON APIs 32 | gem 'devise_token_auth', github: "lynndylanhurley/devise_token_auth", branch: "master" 33 | gem 'omniauth' 34 | 35 | # CanCan is an authorization library for Ruby on Rails which restricts what resources a given user is allowed to access. 36 | gem 'cancancan' 37 | 38 | # Faster & modern implementation of client to integrate Rails with Redis 39 | # configuration in: config/initializers/readthis.rb (Fault Tolerant enable) 40 | # Read more: https://github.com/sorentwo/readthis 41 | gem 'redis' 42 | gem 'readthis' 43 | gem 'hiredis' 44 | 45 | # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible 46 | gem 'rack-cors' 47 | 48 | # Sidekiq as delay job manager 49 | gem 'sidekiq', '~> 4.1.2' 50 | 51 | # Cron for JOBS. Read more: https://github.com/ondrejbartas/sidekiq-cron 52 | gem 'sidekiq-cron', '~> 0.4.0' 53 | gem 'sidekiq-failures', '~> 0.4.5' 54 | gem 'sidekiq-statistic' 55 | gem 'sinatra', github: 'sinatra/sinatra', branch: 'master' 56 | 57 | # Use ActiveModel has_secure_password 58 | # gem 'bcrypt', '~> 3.1.7' 59 | 60 | # Use Capistrano for deployment 61 | # gem 'capistrano-rails', group: :development 62 | 63 | group :development, :test do 64 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 65 | gem 'pry' 66 | gem 'pry-byebug' 67 | gem 'byebug', platform: :mri 68 | 69 | # Read more: https://github.com/collectiveidea/json_spec 70 | gem 'json_spec' 71 | 72 | # Read more: https://github.com/charliesome/better_errors 73 | # gem "better_errors" 74 | # gem 'binding_of_caller' 75 | 76 | # Read more: https://github.com/awesome-print/awesome_print 77 | # run ap User.all to see afect 78 | gem "awesome_print", require:"ap" 79 | 80 | # Integrate Rails project with Rails Panel (chrome extension) 81 | # Read More: https://github.com/dejan/rails_panel 82 | gem 'meta_request' 83 | 84 | # Use RSpec for specs 85 | gem "rspec-rails" 86 | 87 | # Automatic generate API documentation based on comments in RSpec 88 | gem 'rspec_api_documentation' 89 | 90 | # RSpec coverage 91 | gem 'simplecov', :require => false 92 | 93 | # Faker 94 | gem 'faker' 95 | 96 | # Use Factory Girl for generating random test data 97 | gem 'factory_girl_rails' 98 | 99 | # Fake email 100 | gem "letter_opener",:require => false 101 | 102 | end 103 | 104 | group :development do 105 | gem 'listen', '~> 3.0.5' 106 | 107 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 108 | gem 'spring' 109 | gem 'spring-watcher-listen', '~> 2.0.0' 110 | 111 | # JSON Schema tooling 112 | # Read more: 113 | # - https://github.com/interagent/prmd 114 | # - https://spacetelescope.github.io/understanding-json-schema/index.html 115 | # gem 'prmd' 116 | end 117 | 118 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 119 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] 120 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/diwaniuk/jbuilder.git 3 | revision: 50e3ca8e714be7ddca229b3db31c6b43175bbf97 4 | specs: 5 | jbuilder (2.4.1) 6 | activesupport (>= 3.0.0, < 5.1) 7 | multi_json (~> 1.2) 8 | 9 | GIT 10 | remote: git://github.com/lynndylanhurley/devise_token_auth.git 11 | revision: 536911c7d3f178637423b77fe1179388ddf62b9e 12 | branch: master 13 | specs: 14 | devise_token_auth (0.1.39) 15 | devise (> 3.5.2, <= 4.2) 16 | rails (< 6) 17 | 18 | GIT 19 | remote: git://github.com/sinatra/sinatra.git 20 | revision: af6dad2a6c31e31617712b15f455b2a3d3eb1c06 21 | branch: master 22 | specs: 23 | sinatra (2.0.0.beta2) 24 | mustermann (= 1.0.0.beta2) 25 | rack (~> 2.0) 26 | rack-protection (= 2.0.0.beta2) 27 | tilt (~> 2.0) 28 | 29 | GEM 30 | remote: https://rubygems.org/ 31 | specs: 32 | actioncable (5.0.0) 33 | actionpack (= 5.0.0) 34 | nio4r (~> 1.2) 35 | websocket-driver (~> 0.6.1) 36 | actionmailer (5.0.0) 37 | actionpack (= 5.0.0) 38 | actionview (= 5.0.0) 39 | activejob (= 5.0.0) 40 | mail (~> 2.5, >= 2.5.4) 41 | rails-dom-testing (~> 2.0) 42 | actionpack (5.0.0) 43 | actionview (= 5.0.0) 44 | activesupport (= 5.0.0) 45 | rack (~> 2.0) 46 | rack-test (~> 0.6.3) 47 | rails-dom-testing (~> 2.0) 48 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 49 | actionview (5.0.0) 50 | activesupport (= 5.0.0) 51 | builder (~> 3.1) 52 | erubis (~> 2.7.0) 53 | rails-dom-testing (~> 2.0) 54 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 55 | activejob (5.0.0) 56 | activesupport (= 5.0.0) 57 | globalid (>= 0.3.6) 58 | activemodel (5.0.0) 59 | activesupport (= 5.0.0) 60 | activerecord (5.0.0) 61 | activemodel (= 5.0.0) 62 | activesupport (= 5.0.0) 63 | arel (~> 7.0) 64 | activesupport (5.0.0) 65 | concurrent-ruby (~> 1.0, >= 1.0.2) 66 | i18n (~> 0.7) 67 | minitest (~> 5.1) 68 | tzinfo (~> 1.1) 69 | addressable (2.4.0) 70 | arel (7.1.2) 71 | awesome_print (1.7.0) 72 | bcrypt (3.1.11) 73 | builder (3.2.2) 74 | byebug (9.0.5) 75 | callsite (0.0.11) 76 | cancancan (1.15.0) 77 | coderay (1.1.1) 78 | concurrent-ruby (1.0.2) 79 | connection_pool (2.2.0) 80 | devise (4.2.0) 81 | bcrypt (~> 3.0) 82 | orm_adapter (~> 0.1) 83 | railties (>= 4.1.0, < 5.1) 84 | responders 85 | warden (~> 1.2.3) 86 | diff-lcs (1.2.5) 87 | docile (1.1.5) 88 | erubis (2.7.0) 89 | factory_girl (4.7.0) 90 | activesupport (>= 3.0.0) 91 | factory_girl_rails (4.7.0) 92 | factory_girl (~> 4.7.0) 93 | railties (>= 3.0.0) 94 | faker (1.6.6) 95 | i18n (~> 0.5) 96 | ffi (1.9.14) 97 | globalid (0.3.7) 98 | activesupport (>= 4.1.0) 99 | hashie (3.4.6) 100 | hiredis (0.6.1) 101 | i18n (0.7.0) 102 | json (2.0.2) 103 | json-schema (2.5.0) 104 | addressable (~> 2.3) 105 | json_spec (1.1.4) 106 | multi_json (~> 1.0) 107 | rspec (>= 2.0, < 4.0) 108 | launchy (2.4.3) 109 | addressable (~> 2.3) 110 | letter_opener (1.4.1) 111 | launchy (~> 2.2) 112 | listen (3.0.8) 113 | rb-fsevent (~> 0.9, >= 0.9.4) 114 | rb-inotify (~> 0.9, >= 0.9.7) 115 | loofah (2.0.3) 116 | nokogiri (>= 1.5.9) 117 | mail (2.6.4) 118 | mime-types (>= 1.16, < 4) 119 | meta_request (0.4.0) 120 | callsite (~> 0.0, >= 0.0.11) 121 | rack-contrib (~> 1.1) 122 | railties (>= 3.0.0, < 5.1.0) 123 | method_source (0.8.2) 124 | mime-types (3.1) 125 | mime-types-data (~> 3.2015) 126 | mime-types-data (3.2016.0521) 127 | mini_portile2 (2.1.0) 128 | minitest (5.9.0) 129 | multi_json (1.12.1) 130 | mustache (1.0.3) 131 | mustermann (1.0.0.beta2) 132 | nio4r (1.2.1) 133 | nokogiri (1.6.8) 134 | mini_portile2 (~> 2.1.0) 135 | pkg-config (~> 1.1.7) 136 | omniauth (1.3.1) 137 | hashie (>= 1.2, < 4) 138 | rack (>= 1.0, < 3) 139 | orm_adapter (0.5.0) 140 | pg (0.18.4) 141 | pkg-config (1.1.7) 142 | pry (0.10.4) 143 | coderay (~> 1.1.0) 144 | method_source (~> 0.8.1) 145 | slop (~> 3.4) 146 | pry-byebug (3.4.0) 147 | byebug (~> 9.0) 148 | pry (~> 0.10) 149 | puma (3.6.0) 150 | rack (2.0.1) 151 | rack-attack (5.0.1) 152 | rack 153 | rack-contrib (1.2.0) 154 | rack (>= 0.9.1) 155 | rack-cors (0.4.0) 156 | rack-protection (2.0.0.beta2) 157 | rack 158 | rack-test (0.6.3) 159 | rack (>= 1.0) 160 | rack-timeout (0.4.2) 161 | rails (5.0.0) 162 | actioncable (= 5.0.0) 163 | actionmailer (= 5.0.0) 164 | actionpack (= 5.0.0) 165 | actionview (= 5.0.0) 166 | activejob (= 5.0.0) 167 | activemodel (= 5.0.0) 168 | activerecord (= 5.0.0) 169 | activesupport (= 5.0.0) 170 | bundler (>= 1.3.0, < 2.0) 171 | railties (= 5.0.0) 172 | sprockets-rails (>= 2.0.0) 173 | rails-dom-testing (2.0.1) 174 | activesupport (>= 4.2.0, < 6.0) 175 | nokogiri (~> 1.6.0) 176 | rails-html-sanitizer (1.0.3) 177 | loofah (~> 2.0) 178 | railties (5.0.0) 179 | actionpack (= 5.0.0) 180 | activesupport (= 5.0.0) 181 | method_source 182 | rake (>= 0.8.7) 183 | thor (>= 0.18.1, < 2.0) 184 | rake (11.3.0) 185 | rb-fsevent (0.9.7) 186 | rb-inotify (0.9.7) 187 | ffi (>= 0.5.0) 188 | readthis (2.0.1) 189 | connection_pool (~> 2.1) 190 | redis (~> 3.0) 191 | redis (3.3.1) 192 | redis-namespace (1.5.2) 193 | redis (~> 3.0, >= 3.0.4) 194 | responders (2.3.0) 195 | railties (>= 4.2.0, < 5.1) 196 | rspec (3.5.0) 197 | rspec-core (~> 3.5.0) 198 | rspec-expectations (~> 3.5.0) 199 | rspec-mocks (~> 3.5.0) 200 | rspec-core (3.5.3) 201 | rspec-support (~> 3.5.0) 202 | rspec-expectations (3.5.0) 203 | diff-lcs (>= 1.2.0, < 2.0) 204 | rspec-support (~> 3.5.0) 205 | rspec-mocks (3.5.0) 206 | diff-lcs (>= 1.2.0, < 2.0) 207 | rspec-support (~> 3.5.0) 208 | rspec-rails (3.5.2) 209 | actionpack (>= 3.0) 210 | activesupport (>= 3.0) 211 | railties (>= 3.0) 212 | rspec-core (~> 3.5.0) 213 | rspec-expectations (~> 3.5.0) 214 | rspec-mocks (~> 3.5.0) 215 | rspec-support (~> 3.5.0) 216 | rspec-support (3.5.0) 217 | rspec_api_documentation (4.8.0) 218 | activesupport (>= 3.0.0) 219 | mustache (~> 1.0, >= 0.99.4) 220 | rspec (~> 3.0, >= 3.0.0) 221 | rufus-scheduler (3.2.2) 222 | sidekiq (4.1.4) 223 | concurrent-ruby (~> 1.0) 224 | connection_pool (~> 2.2, >= 2.2.0) 225 | redis (~> 3.2, >= 3.2.1) 226 | sinatra (>= 1.4.7) 227 | sidekiq-cron (0.4.3) 228 | redis-namespace (>= 1.5.2) 229 | rufus-scheduler (>= 2.0.24) 230 | sidekiq (>= 4.0.0) 231 | sidekiq-failures (0.4.5) 232 | sidekiq (>= 2.16.0) 233 | sidekiq-statistic (1.2.0) 234 | sidekiq (>= 3.3.4, < 5) 235 | simplecov (0.12.0) 236 | docile (~> 1.1.0) 237 | json (>= 1.8, < 3) 238 | simplecov-html (~> 0.10.0) 239 | simplecov-html (0.10.0) 240 | slop (3.6.0) 241 | spring (1.7.2) 242 | spring-watcher-listen (2.0.0) 243 | listen (>= 2.7, < 4.0) 244 | spring (~> 1.2) 245 | sprockets (3.7.0) 246 | concurrent-ruby (~> 1.0) 247 | rack (> 1, < 3) 248 | sprockets-rails (3.2.0) 249 | actionpack (>= 4.0) 250 | activesupport (>= 4.0) 251 | sprockets (>= 3.0.0) 252 | sqlite3 (1.3.11) 253 | thor (0.19.1) 254 | thread_safe (0.3.5) 255 | tilt (2.0.5) 256 | tzinfo (1.2.2) 257 | thread_safe (~> 0.1) 258 | warden (1.2.6) 259 | rack (>= 1.0) 260 | websocket-driver (0.6.4) 261 | websocket-extensions (>= 0.1.0) 262 | websocket-extensions (0.1.2) 263 | yajl-ruby (1.2.1) 264 | 265 | PLATFORMS 266 | ruby 267 | 268 | DEPENDENCIES 269 | awesome_print 270 | byebug 271 | cancancan 272 | devise_token_auth! 273 | factory_girl_rails 274 | faker 275 | hiredis 276 | jbuilder! 277 | json-schema 278 | json_spec 279 | letter_opener 280 | listen (~> 3.0.5) 281 | meta_request 282 | omniauth 283 | pg 284 | pry 285 | pry-byebug 286 | puma (~> 3.0) 287 | rack-attack 288 | rack-cors 289 | rack-timeout 290 | rails (= 5.0.0) 291 | readthis 292 | redis 293 | rspec-rails 294 | rspec_api_documentation 295 | sidekiq (~> 4.1.2) 296 | sidekiq-cron (~> 0.4.0) 297 | sidekiq-failures (~> 0.4.5) 298 | sidekiq-statistic 299 | simplecov 300 | sinatra! 301 | spring 302 | spring-watcher-listen (~> 2.0.0) 303 | sqlite3 304 | tzinfo-data 305 | yajl-ruby 306 | 307 | BUNDLED WITH 308 | 1.12.5 309 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Rails 5 API starter 2 | 3 | Rails 5 API starter is a boilerplate which helps you build fast, secure and efficient API for applications. Template based on automatically generated structure of directory and settings which are default delivered by --api switch. Additional to settings are added and initially configure useful Gems, which are often used in Rails stack application. 4 | 5 |

6 | 7 |

8 | 9 | ## Features 10 | 11 | - [omniauth](https://github.com/intridea/omniauth ) 12 | - [devise](https://github.com/plataformatec/devise) 13 | - [devise_token_auth](https://github.com/lynndylanhurley/devise_token_auth) 14 | - [cancancan](https://github.com/CanCanCommunity/cancancan) 15 | - [jbuilder](https://github.com/rails/jbuilder) 16 | - [rspec-api-documentation](https://github.com/zipmark/rspec_api_documentation ) 17 | - [yard](https://github.com/lsegal/yard) 18 | - [rspec-rails](https://github.com/rspec/rspec-rails) 19 | - [json_spec](https://github.com/collectiveidea/json_spec) 20 | - [factory-girl](https://github.com/thoughtbot/factory_girl) 21 | - [faker]( https://github.com/stympy/faker) 22 | - [simpleconv](https://github.com/colszowka/simplecov) 23 | - [rack-attacker](https://github.com/kickstarter/rack-attack ) 24 | - [rack-timeout]( https://github.com/heroku/rack-timeout) 25 | - [readthis](https://github.com/sorentwo/readthis) 26 | - [hiredis](https://github.com/redis/hiredis) 27 | - [spirng](https://github.com/rails/spring ) 28 | - [better_errors](https://github.com/charliesome/better_errors) 29 | - [awesome_print](https://github.com/awesome-print/awesome_print) 30 | - [rails_panel](https://github.com/dejan/rails_panel) 31 | - [pry-byebug](https://github.com/deivid-rodriguez/pry-byebug) 32 | - [sidekiq](https://github.com/mperham/sidekiq) 33 | - [prmd](https://github.com/interagent/prmd) 34 | 35 | ### Installation process 36 | 37 | ##### Requirements 38 | 39 | Boilerplate based on Docker container. To start using them, first, we have to make sure that Docker Engine and Docker compose tool are installed. 40 | 41 | - Compose 1.6.0+ 42 | - Docker Engine 1.10.0+ 43 | 44 | ##### Build 45 | 46 | ``` 47 | $ git git@github.com:Hawatel/rails5-api-starter.git 48 | $ docker-compose build 49 | $ docker-compose run web bundle 50 | $ docker-compose run web rails db:create 51 | $ docker-compose run web rails db:migrate 52 | ``` 53 | 54 | ### Getting Started 55 | 56 | To start the server you only need to run the following magic command: 57 | 58 | ``` 59 | $ docker-compose up 60 | ``` 61 | 62 | #### Rename project 63 | 64 | It is only necessary from the perspective of the framework to change the application name in config/application.rb file. 65 | 66 | ``` 67 | ... 68 | module HawatelApi5Starterkit # CHANGE HERE 69 | class Application < Rails::Application 70 | # Settings in config/environments/* take precedence over those specified here. 71 | # Application configuration should go into files in config/initializers 72 | # -- all .rb files in that directory are automatically loaded. 73 | 74 | # Only loads a smaller set of middleware suitable for API only apps. 75 | # Middleware like session, flash, cookies can be added back manually. 76 | # Skip views, helpers and assets when generating a new resource. 77 | config.api_only = true 78 | 79 | # Use Rack Attack 80 | config.middleware.use Rack::Attack 81 | end 82 | end 83 | ``` 84 | 85 | #### Update Gemset 86 | 87 | To avoid install gems from scratch in each time when Gemfile will be updated, boilerplate has implemented persistent, cross-container dedicated volume for gems. 88 | Now in case when new entry to Gemfile is added, just run below command to update state: 89 | 90 | ``` 91 | $ docker-compose run web bundle 92 | ``` 93 | 94 | #### Debugging 95 | 96 | ##### Rails in Chrome 97 | 98 | RailsPanel is a Chrome extension for Rails development that will end your tailing of development.log. Have all information about your Rails app requests right there in the Developer Tools panel. 99 | To use this you will need to install Chrome extension from this [link](https://chrome.google.com/webstore/detail/railspanel/gjpfobpafnhjhbajcjgccbbdofdckggg) . 100 | 101 | 102 | ### RSpec 103 | 104 | Running your test suite is done quite easily. You have to just set RAILS_ENV to test and execute rspec command the same way you would run your tests locally: 105 | 106 | ``` 107 | $ docker-compose run -e "RAILS_ENV=test" rspec 108 | ``` 109 | 110 | In case when you need initialize or migrate database in test env call rails db:create or db:migrate: 111 | 112 | ``` 113 | $ docker-compose run -e "RAILS_ENV=test" web rails db:create 114 | $ docker-compose run -e "RAILS_ENV=test" web rails db:migrate 115 | ``` 116 | 117 | #### API Documentation based on rspec-api-documentation 118 | 119 | ``` 120 | $ docker-compose run -e "RAILS_ENV=test" web rake docs:generate 121 | ``` 122 | 123 | 124 | ## License 125 | 126 | The Starter Kit is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 127 | 128 | ## Useful links 129 | 130 | #### Design API 131 | - https://geemus.gitbooks.io/http-api-design/content/en/ 132 | - https://labs.omniti.com/labs/jsend 133 | - http://jsonapi.org/ 134 | 135 | ## TODO 136 | - https://github.com/phatworx/devise_security_extension - Add Devise security extension 137 | 138 | 139 | -------------------------------------------------------------------------------- /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_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading. 2 | module ApplicationCable 3 | class Channel < ActionCable::Channel::Base 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading. 2 | module ApplicationCable 3 | class Connection < ActionCable::Connection::Base 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::API 2 | include DeviseTokenAuth::Concerns::SetUserByToken 3 | include ActionController::Caching 4 | include CanCan::ControllerAdditions 5 | 6 | end 7 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/public_controller.rb: -------------------------------------------------------------------------------- 1 | class PublicController < ApplicationController 2 | 3 | def index 4 | authorize! :read, :all 5 | 6 | @msg = "Hello Word" 7 | # Generate uniq key for cache. 8 | @cache_key = "users/#{User.maximum(:updated_at)}" 9 | 10 | #Cache SQL query 11 | # @users = Rails.cache.fetch(@cache_key, expires_in: 10.minutes.to_i) do 12 | # User.all 13 | # end 14 | end 15 | 16 | # only admin can create new stuff 17 | def create 18 | authorize! :manage, :all 19 | end 20 | 21 | end -------------------------------------------------------------------------------- /app/controllers/todos_controller.rb: -------------------------------------------------------------------------------- 1 | class TodosController < ApplicationController 2 | before_action :set_todo, only: [:show, :update, :destroy] 3 | before_action :authenticate_user! 4 | 5 | # GET /todos 6 | # GET /todos.json 7 | def index 8 | @todos = Todo.all 9 | end 10 | 11 | # GET /todos/1 12 | # GET /todos/1.json 13 | def show 14 | if Todo.cache_find(params[:id]) 15 | @todos = Todo.cache_find(params[:id]) 16 | end 17 | end 18 | 19 | # POST /todos 20 | # POST /todos.json 21 | def create 22 | @todo = Todo.new(todo_params) 23 | if @todo.save 24 | render :show, status: :created, location: @todo 25 | else 26 | render json: @todo.errors, status: :unprocessable_entity 27 | end 28 | end 29 | 30 | # PATCH/PUT /todos/1 31 | # PATCH/PUT /todos/1.json 32 | def update 33 | if @todo.update(todo_params) 34 | render :show, status: :ok, location: @todo 35 | else 36 | render json: @todo.errors, status: :unprocessable_entity 37 | end 38 | end 39 | 40 | 41 | # DELETE /todos/1 42 | # DELETE /todos/1.json 43 | def destroy 44 | @todo.destroy 45 | end 46 | 47 | private 48 | # Use callbacks to share common setup or constraints between actions. 49 | def set_todo 50 | if Todo.cache_find(params[:id]) 51 | @todo = Todo.cache_find(params[:id]) 52 | end 53 | end 54 | 55 | # Never trust parameters from the scary internet, only allow the white list through. 56 | def todo_params 57 | params.require(:todo).permit(:title, :completed, :order) 58 | end 59 | 60 | end 61 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /app/models/ability.rb: -------------------------------------------------------------------------------- 1 | class Ability 2 | include CanCan::Ability 3 | 4 | def initialize(user) 5 | 6 | user ||= User.new # guest user (not logged in) 7 | 8 | if user.admin? 9 | can :manage, :all 10 | else 11 | can :read, :all 12 | end 13 | 14 | # Define abilities for the passed in user here. For example: 15 | # 16 | # user ||= User.new # guest user (not logged in) 17 | # if user.admin? 18 | # can :manage, :all 19 | # else 20 | # can :read, :all 21 | # end 22 | # 23 | # The first argument to `can` is the action you are giving the user 24 | # permission to do. 25 | # If you pass :manage it will apply to every action. Other common actions 26 | # here are :read, :create, :update and :destroy. 27 | # 28 | # The second argument is the resource the user can perform the action on. 29 | # If you pass :all it will apply to every resource. Otherwise pass a Ruby 30 | # class of the resource. 31 | # 32 | # The third argument is an optional hash of conditions to further filter the 33 | # objects. 34 | # For example, here the user can only update published articles. 35 | # 36 | # can :update, Article, :published => true 37 | # 38 | # See the wiki for details: 39 | # https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/todo.rb: -------------------------------------------------------------------------------- 1 | class Todo < ApplicationRecord 2 | 3 | after_commit :flush_cache 4 | 5 | def flush_cache 6 | Rails.cache.delete([self.class.name, id]) 7 | end 8 | 9 | def self.cache_find(id) 10 | Rails.cache.fetch([name, id]) { find(id) } 11 | end 12 | 13 | end 14 | 15 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | # Include default devise modules. 3 | devise :database_authenticatable, :registerable, 4 | :recoverable, :rememberable, :trackable, :validatable, 5 | :confirmable, :omniauthable 6 | include DeviseTokenAuth::Concerns::User 7 | end 8 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/views/public/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | # get json from cache, if doson't exist execute code from bloc do...end and save in cache 2 | json.cache! ["users/#{@cache_key}"], expired_in: 60.minutes.to_i do 3 | json.status "success" 4 | json.data do 5 | json.message @msg 6 | json.array!(User.all) do |user| 7 | json.extract! user, :id, :email, :current_sign_in_ip 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/views/todos/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.status "success" 2 | json.data do 3 | json.todos do 4 | json.array!(@todos) do |todo| 5 | json.extract! todo, :id, :title, :completed, :order 6 | json.url todo_url(todo, format: :json) 7 | end 8 | end 9 | end 10 | 11 | # json.employess do 12 | # 13 | # @users.each do |data| 14 | # json.data do 15 | # json.name 'Daniel' 16 | # json.surname 'Iwaniuk' 17 | # end 18 | # end 19 | # 20 | # 21 | # json.users do 22 | # json.array! @users.each do |user| 23 | # json.type 'regular' 24 | # json.surname user 25 | # json.role 'admin' 26 | # end 27 | # end 28 | # 29 | # json.users2 do 30 | # json.array! @users2.each do |user2| 31 | # json.type 'regular' 32 | # json.name user2[:name] 33 | # json.surname user2[:surname] 34 | # if user2[:name] == 'Daniel' 35 | # json.role 'admin' 36 | # else 37 | # json.role 'read-only' 38 | # end 39 | # end 40 | # end 41 | # 42 | # # get value from methods 43 | # json.(@article, :id, :name, :published_at) 44 | # 45 | # json.attachments @users.each do |user| 46 | # json.surname user 47 | # json.role 'admin' 48 | # end 49 | # 50 | # end 51 | 52 | # RESPOND 53 | # { 54 | # "status":"success", 55 | # "data": { 56 | # "users":[ 57 | # {"type":"regular","surname":"Daniel","role":"admin"}, 58 | # {"type":"regular","surname":"Michal","role":"admin"} 59 | # ] 60 | # } 61 | # } 62 | 63 | # GET /users. 64 | # json.status "success" 65 | # json.data do 66 | # json.users do 67 | # json.array! @users.each do |user| 68 | # json.type 'regular' 69 | # json.surname user 70 | # json.role 'admin' 71 | # end 72 | # end 73 | # end 74 | 75 | # RESPOND 76 | # { 77 | # "status":"success", 78 | # "data": { 79 | # "users":[ 80 | # {"type":"regular","surname":"Daniel","role":"admin"}, 81 | # {"type":"regular","surname":"Michal","role":"admin"} 82 | # ] 83 | # } 84 | # } 85 | 86 | 87 | # # GET /users/1.json 88 | # json.status "success" 89 | # json.data do 90 | # json.users 91 | # json.type 'regular' 92 | # json.surname 'usersname' 93 | # json.role 'admin' 94 | # end 95 | # 96 | # { 97 | # "status": "success", 98 | # "data": { 99 | # "type": "regular", 100 | # "surname": "usersname", 101 | # "role": "admin" 102 | # } 103 | # } 104 | 105 | # DELETE /users/1.json 106 | # json.status "success" 107 | # json.data "null" 108 | # 109 | # { 110 | # "status": "success", 111 | # "data": "null" 112 | # } 113 | 114 | 115 | # == FAIL === 116 | # json.status "fail" 117 | # json.data do 118 | # json.title "Position is required" 119 | # end 120 | # 121 | # { 122 | # "status": "fail", 123 | # "data": { 124 | # "title": "Position is required" 125 | # } 126 | # } 127 | -------------------------------------------------------------------------------- /app/views/todos/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | if @todos 2 | json.status "success" 3 | json.data do 4 | json.extract! @todos, :id, :title, :completed, :order, :created_at, :updated_at 5 | end 6 | else 7 | json.status "fail" 8 | json.data do 9 | json.title "Position dosn't exist" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /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/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | APP_PATH = File.expand_path('../config/application', __dir__) 8 | require_relative '../config/boot' 9 | require 'rails/commands' 10 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | require_relative '../config/boot' 8 | require 'rake' 9 | Rake.application.run 10 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a starting point to setup your application. 15 | # Add necessary setup steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | # puts "\n== Copying sample files ==" 22 | # unless File.exist?('config/database.yml') 23 | # cp 'config/database.yml.sample', 'config/database.yml' 24 | # end 25 | 26 | puts "\n== Preparing database ==" 27 | system! 'bin/rails db:setup' 28 | 29 | puts "\n== Removing old logs and tempfiles ==" 30 | system! 'bin/rails log:clear tmp:clear' 31 | 32 | puts "\n== Restarting application server ==" 33 | system! 'bin/rails restart' 34 | end 35 | -------------------------------------------------------------------------------- /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 | Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) } 12 | gem 'spring', match[1] 13 | require 'spring/binstub' 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | puts "\n== Updating database ==" 22 | system! 'bin/rails db:migrate' 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! 'bin/rails log:clear tmp:clear' 26 | 27 | puts "\n== Restarting application server ==" 28 | system! 'bin/rails restart' 29 | end 30 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require "rails" 4 | # Pick the frameworks you want: 5 | require "active_model/railtie" 6 | require "active_job/railtie" 7 | require "active_record/railtie" 8 | require "action_controller/railtie" 9 | require "action_mailer/railtie" 10 | require "action_view/railtie" 11 | require "action_cable/engine" 12 | # require "sprockets/railtie" 13 | require "rails/test_unit/railtie" 14 | 15 | # Require the gems listed in Gemfile, including any gems 16 | # you've limited to :test, :development, or :production. 17 | Bundler.require(*Rails.groups) 18 | 19 | module HawatelApi5Starterkit 20 | class Application < Rails::Application 21 | # Settings in config/environments/* take precedence over those specified here. 22 | # Application configuration should go into files in config/initializers 23 | # -- all .rb files in that directory are automatically loaded. 24 | 25 | # Only loads a smaller set of middleware suitable for API only apps. 26 | # Middleware like session, flash, cookies can be added back manually. 27 | # Skip views, helpers and assets when generating a new resource. 28 | config.api_only = true 29 | 30 | # Use Rack Attack 31 | config.middleware.use Rack::Attack 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | # Action Cable uses Redis by default to administer connections, channels, and sending/receiving messages over the WebSocket. 2 | production: 3 | adapter: redis 4 | url: redis://localhost:6379/1 5 | 6 | development: 7 | adapter: async 8 | 9 | test: 10 | adapter: async 11 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | encoding: unicode 4 | pool: 5 5 | timeout: 5000 6 | username: postgres 7 | password: SecurePasswordPG 8 | host: postgres 9 | port: 5432 10 | 11 | development: 12 | <<: *default 13 | database: app_development 14 | 15 | # Warning: The database defined as "test" will be erased and 16 | # re-generated from your development database when you run 17 | # "rake". Do not set this db to the same as development or 18 | # production. 19 | test: 20 | <<: *default 21 | database: app_test -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 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. 13 | config.consider_all_requests_local = true 14 | 15 | # Show errors is HTML formatl 16 | config.debug_exception_response_format = :default 17 | 18 | # Enable/disable caching. By default caching is disabled. 19 | if Rails.root.join('tmp/caching-dev.txt').exist? 20 | config.action_controller.perform_caching = true 21 | config.cache_store = :readthis_store, { 22 | expires_in: 24.hours.to_i, 23 | redis: { url: "#{ENV['REDIS_URL']}/0/cache", driver: :hiredis } 24 | } 25 | config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=172800' } 26 | else 27 | config.action_controller.perform_caching = false 28 | config.cache_store = [:null_store] 29 | end 30 | 31 | # Fake email server 32 | config.action_mailer.delivery_method = :file 33 | config.action_mailer.file_settings = { :location => Rails.root.join('tmp/mail') } 34 | config.action_mailer.default_url_options = { :host => "http://localhost:3000" } 35 | 36 | # Don't care if the mailer can't send. 37 | config.action_mailer.raise_delivery_errors = false 38 | 39 | config.action_mailer.perform_caching = false 40 | 41 | # Print deprecation notices to the Rails logger. 42 | config.active_support.deprecation = :log 43 | 44 | # Raise an error on page load if there are pending migrations. 45 | config.active_record.migration_error = :page_load 46 | 47 | # Better errors 48 | # TODO fix issue with better error 49 | # BetterErrors::Middleware.allow_ip! "0.0.0.0/0" 50 | 51 | # Raises error for missing translations 52 | # config.action_view.raise_on_missing_translations = true 53 | 54 | # Use an evented file watcher to asynchronously detect changes in source code, 55 | # routes, locales, etc. This feature depends on the listen gem. 56 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 57 | end 58 | -------------------------------------------------------------------------------- /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 | # Disable serving static files from the `/public` folder by default since 18 | # Apache or NGINX already handles this. 19 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 20 | 21 | # Enable/disable caching. By default caching is disabled. 22 | if Rails.root.join('tmp/caching-prod.txt').exist? 23 | config.action_controller.perform_caching = true 24 | config.cache_store = :readthis_store, { 25 | expires_in: 30.minutes.to_i, 26 | redis: { url: "#{ENV['REDIS_URL']}/0/cache", driver: :hiredis } 27 | } 28 | config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=172800' } 29 | else 30 | config.action_controller.perform_caching = false 31 | config.cache_store = [:null_store] 32 | end 33 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 34 | # config.action_controller.asset_host = 'http://assets.example.com' 35 | 36 | # Specifies the header that your server uses for sending files. 37 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 38 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 39 | 40 | # Action Cable endpoint configuration 41 | # config.action_cable.url = 'wss://example.com/cable' 42 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 43 | 44 | # Don't mount Action Cable in the main server process. 45 | # config.action_cable.mount_path = nil 46 | 47 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 48 | # config.force_ssl = true 49 | 50 | # Use the lowest log level to ensure availability of diagnostic information 51 | # when problems arise. 52 | config.log_level = :info 53 | 54 | # Prepend all log lines with the following tags. 55 | config.log_tags = [ :request_id ] 56 | 57 | # Use a different cache store in production. 58 | # config.cache_store = :mem_cache_store 59 | 60 | # Use a real queuing backend for Active Job (and separate queues per environment) 61 | # config.active_job.queue_adapter = :resque 62 | # config.active_job.queue_name_prefix = "hawatel-api5-starterkit_#{Rails.env}" 63 | config.action_mailer.perform_caching = false 64 | 65 | # Ignore bad email addresses and do not raise email delivery errors. 66 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 67 | # config.action_mailer.raise_delivery_errors = false 68 | 69 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 70 | # the I18n.default_locale when a translation cannot be found). 71 | config.i18n.fallbacks = true 72 | 73 | # Send deprecation notices to registered listeners. 74 | config.active_support.deprecation = :notify 75 | 76 | # Use default logging formatter so that PID and timestamp are not suppressed. 77 | config.log_formatter = ::Logger::Formatter.new 78 | 79 | # Use a different logger for distributed setups. 80 | # require 'syslog/logger' 81 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 82 | 83 | if ENV["RAILS_LOG_TO_STDOUT"].present? 84 | logger = ActiveSupport::Logger.new(STDOUT) 85 | logger.formatter = config.log_formatter 86 | config.logger = ActiveSupport::TaggedLogging.new(logger) 87 | end 88 | 89 | # Do not dump schema after migrations. 90 | config.active_record.dump_schema_after_migration = false 91 | end 92 | -------------------------------------------------------------------------------- /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 public file server for tests with Cache-Control for performance. 16 | config.public_file_server.enabled = true 17 | config.public_file_server.headers = { 18 | 'Cache-Control' => 'public, max-age=3600' 19 | } 20 | 21 | # Show full error reports and disable caching. 22 | config.consider_all_requests_local = true 23 | config.action_controller.perform_caching = false 24 | config.cache_store = [:null_store] 25 | 26 | # Raise exceptions instead of rendering exception templates. 27 | config.action_dispatch.show_exceptions = false 28 | 29 | # Disable request forgery protection in test environment. 30 | config.action_controller.allow_forgery_protection = false 31 | config.action_mailer.perform_caching = false 32 | 33 | # Tell Action Mailer not to deliver emails to the real world. 34 | # The :test delivery method accumulates sent emails in the 35 | # ActionMailer::Base.deliveries array. 36 | config.action_mailer.delivery_method = :test 37 | 38 | # Print deprecation notices to the stderr. 39 | config.active_support.deprecation = :stderr 40 | 41 | # Send test email 42 | config.action_mailer.default_url_options = { :host => "localhost" } 43 | 44 | # Raises error for missing translations 45 | # config.action_view.raise_on_missing_translations = true 46 | end 47 | -------------------------------------------------------------------------------- /config/initializers/active_record_belongs_to_required_by_default.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Require `belongs_to` associations by default. This is a new Rails 5.0 4 | # default, so it is introduced as a configuration option to ensure that apps 5 | # made on earlier versions of Rails are not affected when upgrading. 6 | Rails.application.config.active_record.belongs_to_required_by_default = true 7 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ApplicationController.renderer.defaults.merge!( 4 | # http_host: 'example.org', 5 | # https: false 6 | # ) 7 | -------------------------------------------------------------------------------- /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/callback_terminator.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Do not halt callback chains when a callback returns false. This is a new 4 | # Rails 5.0 default, so it is introduced as a configuration option to ensure 5 | # that apps made with earlier versions of Rails are not affected when upgrading. 6 | ActiveSupport.halt_callback_chains_on_return_false = false 7 | -------------------------------------------------------------------------------- /config/initializers/cors.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Avoid CORS issues when API is called from the frontend app. 4 | # Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests. 5 | 6 | # Read more: https://github.com/cyu/rack-cors 7 | 8 | Rails.application.config.middleware.insert_before 0, Rack::Cors do 9 | allow do 10 | origins 'localhost.com' 11 | 12 | resource '*', 13 | headers: :any, 14 | methods: [:get, :post, :put, :patch, :delete, :options, :head] 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /config/initializers/devise.rb: -------------------------------------------------------------------------------- 1 | Devise.setup do |config| 2 | # The e-mail address that mail will appear to be sent from 3 | # If absent, mail is sent from "please-change-me-at-config-initializers-devise@example.com" 4 | config.mailer_sender = "support@hawatel.com" 5 | 6 | # If using rails-api, you may want to tell devise to not use ActionDispatch::Flash 7 | # middleware b/c rails-api does not include it. 8 | # See: http://stackoverflow.com/q/19600905/806956 9 | config.navigational_formats = [:json] 10 | 11 | # email regex 12 | config.email_regexp = /\A[^@\s]+@([^@\s]+\.)+[^@\W]+\z/ 13 | 14 | end -------------------------------------------------------------------------------- /config/initializers/devise_token_auth.rb: -------------------------------------------------------------------------------- 1 | DeviseTokenAuth.setup do |config| 2 | # By default the authorization headers will change after each request. The 3 | # client is responsible for keeping track of the changing tokens. Change 4 | # this to false to prevent the Authorization header from changing after 5 | # each request. 6 | config.change_headers_on_each_request = false 7 | 8 | # By default, users will need to re-authenticate after 2 weeks. This setting 9 | # determines how long tokens will remain valid after they are issued. 10 | config.token_lifespan = 2.weeks 11 | 12 | # Sets the max number of concurrent devices per user, which is 10 by default. 13 | # After this limit is reached, the oldest tokens will be removed. 14 | config.max_number_of_devices = 5 15 | 16 | # Sometimes it's necessary to make several requests to the API at the same 17 | # time. In this case, each request in the batch will need to share the same 18 | # auth token. This setting determines how far apart the requests can be while 19 | # still using the same auth token. 20 | # config.batch_request_buffer_throttle = 5.seconds 21 | 22 | # This route will be the prefix for all oauth2 redirect callbacks. For 23 | # example, using the default '/omniauth', the github oauth2 provider will 24 | # redirect successful authentications to '/omniauth/github/callback' 25 | # config.omniauth_prefix = "/omniauth" 26 | 27 | # By default sending current password is not needed for the password update. 28 | # Uncomment to enforce current_password param to be checked before all 29 | # attribute updates. Set it to :password if you want it to be checked only if 30 | # password is updated. 31 | # config.check_current_password_before_update = :attributes 32 | 33 | # By default, only Bearer Token authentication is implemented out of the box. 34 | # If, however, you wish to integrate with legacy Devise authentication, you can 35 | # do so by enabling this flag. NOTE: This feature is highly experimental! 36 | # enable_standard_devise_support = false 37 | end 38 | -------------------------------------------------------------------------------- /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/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/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_attack.rb: -------------------------------------------------------------------------------- 1 | class Rack::Attack 2 | 3 | ### Configure Cache ### 4 | 5 | # If you don't want to use Rails.cache (Rack::Attack's default), then 6 | # configure it here. 7 | # 8 | # Note: The store is only used for throttling (not blacklisting and 9 | # whitelisting). It must implement .increment and .write like 10 | # ActiveSupport::Cache::Store 11 | 12 | # Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new 13 | 14 | ### Throttle Spammy Clients ### 15 | 16 | # If any single client IP is making tons of requests, then they're 17 | # probably malicious or a poorly-configured scraper. Either way, they 18 | # don't deserve to hog all of the app server's CPU. Cut them off! 19 | # 20 | # Note: If you're serving assets through rack, those requests may be 21 | # counted by rack-attack and this throttle may be activated too 22 | # quickly. If so, enable the condition to exclude them from tracking. 23 | 24 | # Throttle all requests by IP (60rpm) 25 | # 26 | # Key: "rack::attack:#{Time.now.to_i/:period}:req/ip:#{req.ip}" 27 | Rack::Attack.throttle('req/ip', :limit => 10, :period => 1.second) do |req| 28 | req.ip # unless req.path.start_with?('/assets') 29 | end 30 | 31 | 32 | # Add to whitelist - allow for all request 33 | # Rack::Attack.whitelist('allow from localhost') do |req| 34 | # # Requests are allowed if the return value is truthy 35 | # '192.168.52.1' == req.ip 36 | # end 37 | 38 | Rack::Attack.throttled_response = lambda do |env| 39 | # name and other data about the matched throttle 40 | body = '{ "status": "error", "message": "To many request from one IP address" }' 41 | logger.warn = "IP temporary blocket by rack-attack. To many request from one IP address!" 42 | # Using 503 because it may make attacker think that they have successfully 43 | # DOSed the site. Rack::Attack returns 429 for throttling by default 44 | [ 503, {}, [body]] 45 | end 46 | 47 | 48 | # Block specifiec IP 49 | # Rack::Attack.blacklist('block 192.168.52.1') do |req| 50 | # # Requests are blocked if the return value is truthy 51 | # '192.168.52.1' == req.ip 52 | # end 53 | 54 | ### Prevent Brute-Force Login Attacks ### 55 | 56 | # The most common brute-force login attack is a brute-force password 57 | # attack where an attacker simply tries a large number of emails and 58 | # passwords to see if any credentials match. 59 | # 60 | # Another common method of attack is to use a swarm of computers with 61 | # different IPs to try brute-forcing a password for a specific account. 62 | 63 | # Throttle POST requests to /login by IP address 64 | # 65 | # Key: "rack::attack:#{Time.now.to_i/:period}:logins/ip:#{req.ip}" 66 | # throttle('logins/ip', :limit => 5, :period => 20.seconds) do |req| 67 | # if req.path == '/login' && req.post? 68 | # req.ip 69 | # end 70 | # end 71 | 72 | # Throttle POST requests to /login by email param 73 | # 74 | # Key: "rack::attack:#{Time.now.to_i/:period}:logins/email:#{req.email}" 75 | # 76 | # Note: This creates a problem where a malicious user could intentionally 77 | # throttle logins for another user and force their login requests to be 78 | # denied, but that's not very common and shouldn't happen to you. (Knock 79 | # on wood!) 80 | # throttle("logins/email", :limit => 5, :period => 20.seconds) do |req| 81 | # if req.path == '/login' && req.post? 82 | # # return the email if present, nil otherwise 83 | # req.params['email'].presence 84 | # end 85 | # end 86 | 87 | ### Custom Throttle Response ### 88 | 89 | # By default, Rack::Attack returns an HTTP 429 for throttled responses, 90 | # which is just fine. 91 | # 92 | # If you want to return 503 so that the attacker might be fooled into 93 | # believing that they've successfully broken your app (or you just want to 94 | # customize the response), then uncomment these lines. 95 | # self.throttled_response = lambda do |env| 96 | # [ 503, # status 97 | # {}, # headers 98 | # ['']] # body 99 | # end 100 | end -------------------------------------------------------------------------------- /config/initializers/rack_timeout.rb: -------------------------------------------------------------------------------- 1 | # For more information please read https://github.com/heroku/rack-timeout 2 | Rack::Timeout.service_timeout = 30 -------------------------------------------------------------------------------- /config/initializers/readthis.rb: -------------------------------------------------------------------------------- 1 | # In some situations it is desirable to keep serving requests from disk or the database if Redis crashes. This can be achieved with connection fault tolerance by enabling it at the top leve 2 | # The default value is false, because while it may work for fetch operations, it isn't compatible with other state-based commands like increment 3 | Readthis.fault_tolerant = true -------------------------------------------------------------------------------- /config/initializers/sidekiq.rb: -------------------------------------------------------------------------------- 1 | include Sidekiq::Worker 2 | 3 | # Configuratopn for Sidekiq Server 4 | Sidekiq.configure_server do |config| 5 | config.redis = { url: "#{ENV['REDIS_URL']}/12" } 6 | end 7 | 8 | # Configuration for Sidekiq client 9 | Sidekiq.configure_client do |config| 10 | config.redis = { url: "#{ENV['REDIS_URL']}/12" } 11 | end 12 | 13 | # Configure Sidekiq cron jobs. Load data from external, YML file 14 | schedule_file = "config/cron_jobs.yml" 15 | if File.exists?(schedule_file) && Sidekiq.server? 16 | Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file) 17 | end -------------------------------------------------------------------------------- /config/initializers/ssl_options.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure SSL options to enable HSTS with subdomains. 4 | Rails.application.config.ssl_options = { hsts: { subdomains: true } } 5 | -------------------------------------------------------------------------------- /config/initializers/to_time_preserves_timezone.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Preserve the timezone of the receiver when calling to `to_time`. 4 | # Ruby 2.4 will change the behavior of `to_time` to preserve the timezone 5 | # when converting to an instance of `Time` instead of the previous behavior 6 | # of converting to the local system timezone. 7 | # 8 | # Rails 5.0 introduced this config option so that apps made with earlier 9 | # versions of Rails are not affected when upgrading. 10 | ActiveSupport.to_time_preserves_timezone = true 11 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # 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 email address has been successfully confirmed." 7 | send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." 8 | send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." 9 | failure: 10 | already_authenticated: "You are already signed in." 11 | inactive: "Your account is not activated yet." 12 | invalid: "Invalid %{authentication_keys} or password." 13 | locked: "Your account is locked." 14 | last_attempt: "You have one more attempt before your account is locked." 15 | not_found_in_database: "Invalid %{authentication_keys} or password." 16 | timeout: "Your session expired. Please sign in again to continue." 17 | unauthenticated: "You need to sign in or sign up before continuing." 18 | unconfirmed: "You have to confirm your email address before continuing." 19 | mailer: 20 | confirmation_instructions: 21 | subject: "Confirmation instructions" 22 | reset_password_instructions: 23 | subject: "Reset password instructions" 24 | unlock_instructions: 25 | subject: "Unlock instructions" 26 | password_change: 27 | subject: "Password Changed" 28 | omniauth_callbacks: 29 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"." 30 | success: "Successfully authenticated from %{kind} account." 31 | passwords: 32 | 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." 33 | send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." 34 | 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." 35 | updated: "Your password has been changed successfully. You are now signed in." 36 | updated_not_active: "Your password has been changed successfully." 37 | registrations: 38 | destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon." 39 | signed_up: "Welcome! You have signed up successfully." 40 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." 41 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." 42 | signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." 43 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address." 44 | updated: "Your account has been updated successfully." 45 | sessions: 46 | signed_in: "Signed in successfully." 47 | signed_out: "Signed out successfully." 48 | already_signed_out: "Signed out successfully." 49 | unlocks: 50 | send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." 51 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." 52 | unlocked: "Your account has been unlocked successfully. Please sign in to continue." 53 | errors: 54 | messages: 55 | already_confirmed: "was already confirmed, please try signing in" 56 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" 57 | expired: "has expired, please request a new one" 58 | not_found: "not found" 59 | not_locked: "was not locked" 60 | not_saved: 61 | one: "1 error prohibited this %{resource} from being saved:" 62 | other: "%{count} errors prohibited this %{resource} from being saved:" 63 | -------------------------------------------------------------------------------- /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/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum, this matches the default thread size of Active Record. 6 | # 7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i 8 | threads threads_count, threads_count 9 | 10 | # Specifies the `port` that Puma will listen on to receive requests, default is 3000. 11 | # 12 | port ENV.fetch("PORT") { 3000 } 13 | 14 | # Specifies the `environment` that Puma will run in. 15 | # 16 | environment ENV.fetch("RAILS_ENV") { "development" } 17 | 18 | # Specifies the number of `workers` to boot in clustered mode. 19 | # Workers are forked webserver processes. If using threads and workers together 20 | # the concurrency of the application would be max `threads` * `workers`. 21 | # Workers do not work on JRuby or Windows (both of which do not support 22 | # processes). 23 | # 24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 25 | 26 | # Use the `preload_app!` method when specifying a `workers` number. 27 | # This directive tells Puma to first boot the application and load code 28 | # before forking the application. This takes advantage of Copy On Write 29 | # process behavior so workers use less memory. If you use this option 30 | # you need to make sure to reconnect any threads in the `on_worker_boot` 31 | # block. 32 | # 33 | # preload_app! 34 | 35 | # The code in the `on_worker_boot` will be called if you are using 36 | # clustered mode by specifying a number of `workers`. After each worker 37 | # process is booted this block will be run, if you are using `preload_app!` 38 | # option you will want to use this block to reconnect to any threads 39 | # or connections that may have been created at application boot, Ruby 40 | # cannot share connections between processes. 41 | # 42 | # on_worker_boot do 43 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) 44 | # end 45 | 46 | # Allow puma to be restarted by `rails restart` command. 47 | plugin :tmp_restart 48 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | ## For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html 3 | 4 | mount_devise_token_auth_for 'User', at: 'auth' 5 | 6 | get '/', to: 'public#index', :defaults => { :format => 'json' } 7 | post '/', to: 'public#create', :defaults => { :format => 'json' } 8 | 9 | resources :todos, :defaults => { :format => 'json' } 10 | 11 | ## Secure access to sidekiq Web Interface by username and passwod 12 | Sidekiq::Web.use Rack::Auth::Basic do |username, password| 13 | username == ENV["SIDEKIQ_USERNAME"] && password == ENV["SIDEKIQ_PASSWORD"] 14 | end if Rails.env.production? 15 | mount Sidekiq::Web => '/sidekiq' 16 | end 17 | -------------------------------------------------------------------------------- /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 `rails 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 | development: 14 | secret_key_base: f1a430c1a22d04648fe4a71363479a8c1e72194672bbab87c69fcf3bfbe1c86bbe96c76cfa115b9731af20bfeba3ae0a178853fa1672b038794a23dcd55c7077 15 | 16 | test: 17 | secret_key_base: c3a7257938b60f57b7586a3b0e4641ae747661720af6abab679ff89762da0379a96fd6374f18ab35f291b7286998b66629ad310155241924bd6147a9bff341b6 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: f1a430c1a22d04648fe4a71363479a8c1e72194672bbab87c69fcf3bfbe1c86bbe96c76cfa115b9731af20bfeba3ae0a178853fa1672b038794a23dcd55c7088 23 | -------------------------------------------------------------------------------- /config/sidekiq.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :concurrency: 5 3 | :pidfile: tmp/pids/sidekiq.pid 4 | staging: 5 | :concurrency: 10 6 | production: 7 | :concurrency: 20 8 | :queues: 9 | - default -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ).each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /coverage/.last_run.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": { 3 | "covered_percent": 78.79 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /coverage/.resultset.json: -------------------------------------------------------------------------------- 1 | { 2 | "RSpec": { 3 | "coverage": { 4 | "/app/spec/support/settings/rspec_api_documentation.rb": [ 5 | 1, 6 | null, 7 | 1, 8 | null 9 | ], 10 | "/app/spec/acceptance/todos_spec.rb": [ 11 | 1, 12 | 1, 13 | 1, 14 | null, 15 | null, 16 | 1, 17 | 1, 18 | 1, 19 | 1, 20 | null, 21 | null, 22 | 1, 23 | null, 24 | 1, 25 | null, 26 | 1, 27 | null, 28 | null, 29 | 1, 30 | null, 31 | 1, 32 | 1, 33 | null, 34 | null, 35 | null, 36 | 1, 37 | 1, 38 | 1, 39 | null, 40 | 1, 41 | 1, 42 | 1, 43 | 1, 44 | 1, 45 | 1, 46 | null, 47 | null, 48 | null, 49 | null, 50 | null, 51 | null, 52 | 1, 53 | 2, 54 | 2, 55 | 2, 56 | 2, 57 | 2, 58 | null 59 | ], 60 | "/app/app/controllers/application_controller.rb": [ 61 | 1, 62 | 1, 63 | 1, 64 | null, 65 | null 66 | ], 67 | "/app/app/models/todo.rb": [ 68 | 1, 69 | null, 70 | 1, 71 | null, 72 | 1, 73 | 1, 74 | null, 75 | null, 76 | 1, 77 | 0, 78 | null, 79 | null, 80 | null, 81 | null 82 | ], 83 | "/app/app/models/application_record.rb": [ 84 | 1, 85 | 1, 86 | null 87 | ], 88 | "/app/app/controllers/todos_controller.rb": [ 89 | 1, 90 | 1, 91 | 1, 92 | null, 93 | null, 94 | null, 95 | 1, 96 | 1, 97 | null, 98 | null, 99 | null, 100 | null, 101 | 1, 102 | 0, 103 | 0, 104 | null, 105 | null, 106 | null, 107 | null, 108 | null, 109 | 1, 110 | 0, 111 | 0, 112 | 0, 113 | null, 114 | 0, 115 | null, 116 | null, 117 | null, 118 | null, 119 | null, 120 | 1, 121 | 0, 122 | 0, 123 | null, 124 | 0, 125 | null, 126 | null, 127 | null, 128 | null, 129 | null, 130 | null, 131 | 1, 132 | 0, 133 | null, 134 | null, 135 | 1, 136 | null, 137 | 1, 138 | 0, 139 | 0, 140 | null, 141 | null, 142 | null, 143 | null, 144 | 1, 145 | 0, 146 | null, 147 | null, 148 | null 149 | ] 150 | }, 151 | "timestamp": 1474980334 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /coverage/.resultset.json.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/.resultset.json.lock -------------------------------------------------------------------------------- /coverage/assets/0.10.0/application.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | 3 | 4 | Blueprint CSS Framework 0.9 5 | http://blueprintcss.org 6 | 7 | * Copyright (c) 2007-Present. See LICENSE for more info. 8 | * See README for instructions on how to use Blueprint. 9 | * For credits and origins, see AUTHORS. 10 | * This is a compressed file. See the sources in the 'src' directory. 11 | 12 | ----------------------------------------------------------------------- */ 13 | 14 | /* reset.css */ 15 | 16 | html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, dialog, figure, footer, header, hgroup, nav, section {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;} 17 | article, aside, dialog, figure, footer, header, hgroup, nav, section {display:block;} 18 | body {line-height:1.5;} 19 | table {border-collapse:separate;border-spacing:0;} 20 | caption, th, td {text-align:left;font-weight:normal;} 21 | table, td, th {vertical-align:middle;} 22 | blockquote:before, blockquote:after, q:before, q:after {content:"";} 23 | blockquote, q {quotes:"" "";} 24 | a img {border:none;} 25 | 26 | /* typography.css */ 27 | html {font-size:100.01%;} 28 | body {font-size:82%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;} 29 | h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;} 30 | h1 {font-size:3em;line-height:1;margin-bottom:0.5em;} 31 | h2 {font-size:2em;margin-bottom:0.75em;} 32 | h3 {font-size:1.5em;line-height:1;margin-bottom:1em;} 33 | h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;} 34 | h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;} 35 | h6 {font-size:1em;font-weight:bold;} 36 | h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;} 37 | p {margin:0 0 1.5em;} 38 | p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;} 39 | p img.right {float:right;margin:1.5em 0 1.5em 1.5em;} 40 | a:focus, a:hover {color:#000;} 41 | a {color:#009;text-decoration:underline;} 42 | blockquote {margin:1.5em;color:#666;font-style:italic;} 43 | strong {font-weight:bold;} 44 | em, dfn {font-style:italic;} 45 | dfn {font-weight:bold;} 46 | sup, sub {line-height:0;} 47 | abbr, acronym {border-bottom:1px dotted #666;} 48 | address {margin:0 0 1.5em;font-style:italic;} 49 | del {color:#666;} 50 | pre {margin:1.5em 0;white-space:pre;} 51 | pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;} 52 | li ul, li ol {margin:0;} 53 | ul, ol {margin:0 1.5em 1.5em 0;padding-left:3.333em;} 54 | ul {list-style-type:disc;} 55 | ol {list-style-type:decimal;} 56 | dl {margin:0 0 1.5em 0;} 57 | dl dt {font-weight:bold;} 58 | dd {margin-left:1.5em;} 59 | table {margin-bottom:1.4em;width:100%;} 60 | th {font-weight:bold;} 61 | thead th {background:#c3d9ff;} 62 | th, td, caption {padding:4px 10px 4px 5px;} 63 | tr.even td {background:#efefef;} 64 | tfoot {font-style:italic;} 65 | caption {background:#eee;} 66 | .small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;} 67 | .large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;} 68 | .hide {display:none;} 69 | .quiet {color:#666;} 70 | .loud {color:#000;} 71 | .highlight {background:#ff0;} 72 | .added {background:#060;color:#fff;} 73 | .removed {background:#900;color:#fff;} 74 | .first {margin-left:0;padding-left:0;} 75 | .last {margin-right:0;padding-right:0;} 76 | .top {margin-top:0;padding-top:0;} 77 | .bottom {margin-bottom:0;padding-bottom:0;} 78 | 79 | /* forms.css */ 80 | label {font-weight:bold;} 81 | fieldset {padding:1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;} 82 | legend {font-weight:bold;font-size:1.2em;} 83 | input[type=text], input[type=password], input.text, input.title, textarea, select {background-color:#fff;border:1px solid #bbb;} 84 | input[type=text]:focus, input[type=password]:focus, input.text:focus, input.title:focus, textarea:focus, select:focus {border-color:#666;} 85 | input[type=text], input[type=password], input.text, input.title, textarea, select {margin:0.5em 0;} 86 | input.text, input.title {width:300px;padding:5px;} 87 | input.title {font-size:1.5em;} 88 | textarea {width:390px;height:250px;padding:5px;} 89 | input[type=checkbox], input[type=radio], input.checkbox, input.radio {position:relative;top:.25em;} 90 | form.inline {line-height:3;} 91 | form.inline p {margin-bottom:0;} 92 | .error, .notice, .success {padding:.8em;margin-bottom:1em;border:2px solid #ddd;} 93 | .error {background:#FBE3E4;color:#8a1f11;border-color:#FBC2C4;} 94 | .notice {background:#FFF6BF;color:#514721;border-color:#FFD324;} 95 | .success {background:#E6EFC2;color:#264409;border-color:#C6D880;} 96 | .error a {color:#8a1f11;} 97 | .notice a {color:#514721;} 98 | .success a {color:#264409;} 99 | .box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;} 100 | hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;} 101 | hr.space {background:#fff;color:#fff;visibility:hidden;} 102 | .clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;} 103 | .clearfix, .container {display:block;} 104 | .clear {clear:both;} 105 | /* 106 | github.com style (c) Vasily Polovnyov 107 | */ 108 | 109 | 110 | pre code { 111 | } 112 | 113 | pre .comment, 114 | pre .template_comment, 115 | pre .diff .header, 116 | pre .javadoc { 117 | color: #998; 118 | font-style: italic 119 | } 120 | 121 | pre .keyword, 122 | pre .css .rule .keyword, 123 | pre .winutils, 124 | pre .javascript .title, 125 | pre .lisp .title { 126 | color: #000; 127 | font-weight: bold 128 | } 129 | 130 | pre .number, 131 | pre .hexcolor { 132 | color: #458 133 | } 134 | 135 | 136 | pre .string, 137 | pre .tag .value, 138 | pre .phpdoc, 139 | pre .tex .formula { 140 | color: #d14 141 | } 142 | 143 | pre .subst { 144 | color: #712; 145 | } 146 | 147 | pre .constant, 148 | pre .title, 149 | pre .id { 150 | color: #900; 151 | font-weight: bold 152 | } 153 | 154 | pre .javascript .title, 155 | pre .lisp .title, 156 | pre .subst { 157 | font-weight: normal 158 | } 159 | 160 | pre .class .title, 161 | pre .haskell .label, 162 | pre .tex .command { 163 | color: #458; 164 | font-weight: bold 165 | } 166 | 167 | pre .tag, 168 | pre .tag .title, 169 | pre .rules .property, 170 | pre .django .tag .keyword { 171 | color: #000080; 172 | font-weight: normal 173 | } 174 | 175 | pre .attribute, 176 | pre .variable, 177 | pre .instancevar, 178 | pre .lisp .body { 179 | color: #008080 180 | } 181 | 182 | pre .regexp { 183 | color: #009926 184 | } 185 | 186 | pre .class { 187 | color: #458; 188 | font-weight: bold 189 | } 190 | 191 | pre .symbol, 192 | pre .ruby .symbol .string, 193 | pre .ruby .symbol .keyword, 194 | pre .ruby .symbol .keymethods, 195 | pre .lisp .keyword, 196 | pre .tex .special, 197 | pre .input_number { 198 | color: #990073 199 | } 200 | 201 | pre .builtin, 202 | pre .built_in, 203 | pre .lisp .title { 204 | color: #0086b3 205 | } 206 | 207 | pre .preprocessor, 208 | pre .pi, 209 | pre .doctype, 210 | pre .shebang, 211 | pre .cdata { 212 | color: #999; 213 | font-weight: bold 214 | } 215 | 216 | pre .deletion { 217 | background: #fdd 218 | } 219 | 220 | pre .addition { 221 | background: #dfd 222 | } 223 | 224 | pre .diff .change { 225 | background: #0086b3 226 | } 227 | 228 | pre .chunk { 229 | color: #aaa 230 | } 231 | 232 | pre .tex .formula { 233 | opacity: 0.5; 234 | } 235 | /* 236 | * jQuery UI CSS Framework @VERSION 237 | * 238 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 239 | * Dual licensed under the MIT or GPL Version 2 licenses. 240 | * http://jquery.org/license 241 | * 242 | * http://docs.jquery.com/UI/Theming/API 243 | */ 244 | 245 | /* Layout helpers 246 | ----------------------------------*/ 247 | 248 | .ui-helper-hidden { display: none; } 249 | .ui-helper-hidden-accessible { position: absolute; left: -99999999px; } 250 | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } 251 | .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } 252 | .ui-helper-clearfix { display: inline-block; } 253 | /* required comment for clearfix to work in Opera \*/ 254 | * html .ui-helper-clearfix { height:1%; } 255 | .ui-helper-clearfix { display:block; } 256 | /* end clearfix */ 257 | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } 258 | 259 | 260 | /* Interaction Cues 261 | ----------------------------------*/ 262 | .ui-state-disabled { cursor: default !important; } 263 | 264 | 265 | /* Icons 266 | ----------------------------------*/ 267 | 268 | /* states and images */ 269 | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } 270 | 271 | 272 | /* Misc visuals 273 | ----------------------------------*/ 274 | 275 | /* Overlays */ 276 | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } 277 | 278 | 279 | /* 280 | * jQuery UI CSS Framework @VERSION 281 | * 282 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 283 | * Dual licensed under the MIT or GPL Version 2 licenses. 284 | * http://jquery.org/license 285 | * 286 | * http://docs.jquery.com/UI/Theming/API 287 | * 288 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px 289 | */ 290 | 291 | 292 | /* Component containers 293 | ----------------------------------*/ 294 | .ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; } 295 | .ui-widget .ui-widget { font-size: 1em; } 296 | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; } 297 | .ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; } 298 | .ui-widget-content a { color: #222222; } 299 | .ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } 300 | .ui-widget-header a { color: #222222; } 301 | 302 | /* Interaction states 303 | ----------------------------------*/ 304 | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; } 305 | .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; } 306 | .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } 307 | .ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; } 308 | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; } 309 | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; } 310 | .ui-widget :active { outline: none; } 311 | 312 | /* Interaction Cues 313 | ----------------------------------*/ 314 | .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; } 315 | .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } 316 | .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } 317 | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } 318 | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } 319 | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } 320 | .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } 321 | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } 322 | 323 | /* Icons 324 | ----------------------------------*/ 325 | 326 | /* states and images */ 327 | .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } 328 | .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } 329 | .ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } 330 | .ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); } 331 | .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } 332 | .ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } 333 | .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } 334 | .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } 335 | 336 | /* positioning */ 337 | .ui-icon-carat-1-n { background-position: 0 0; } 338 | .ui-icon-carat-1-ne { background-position: -16px 0; } 339 | .ui-icon-carat-1-e { background-position: -32px 0; } 340 | .ui-icon-carat-1-se { background-position: -48px 0; } 341 | .ui-icon-carat-1-s { background-position: -64px 0; } 342 | .ui-icon-carat-1-sw { background-position: -80px 0; } 343 | .ui-icon-carat-1-w { background-position: -96px 0; } 344 | .ui-icon-carat-1-nw { background-position: -112px 0; } 345 | .ui-icon-carat-2-n-s { background-position: -128px 0; } 346 | .ui-icon-carat-2-e-w { background-position: -144px 0; } 347 | .ui-icon-triangle-1-n { background-position: 0 -16px; } 348 | .ui-icon-triangle-1-ne { background-position: -16px -16px; } 349 | .ui-icon-triangle-1-e { background-position: -32px -16px; } 350 | .ui-icon-triangle-1-se { background-position: -48px -16px; } 351 | .ui-icon-triangle-1-s { background-position: -64px -16px; } 352 | .ui-icon-triangle-1-sw { background-position: -80px -16px; } 353 | .ui-icon-triangle-1-w { background-position: -96px -16px; } 354 | .ui-icon-triangle-1-nw { background-position: -112px -16px; } 355 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } 356 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } 357 | .ui-icon-arrow-1-n { background-position: 0 -32px; } 358 | .ui-icon-arrow-1-ne { background-position: -16px -32px; } 359 | .ui-icon-arrow-1-e { background-position: -32px -32px; } 360 | .ui-icon-arrow-1-se { background-position: -48px -32px; } 361 | .ui-icon-arrow-1-s { background-position: -64px -32px; } 362 | .ui-icon-arrow-1-sw { background-position: -80px -32px; } 363 | .ui-icon-arrow-1-w { background-position: -96px -32px; } 364 | .ui-icon-arrow-1-nw { background-position: -112px -32px; } 365 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } 366 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } 367 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } 368 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } 369 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } 370 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } 371 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } 372 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } 373 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; } 374 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } 375 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } 376 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } 377 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } 378 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } 379 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } 380 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } 381 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } 382 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } 383 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } 384 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } 385 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } 386 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } 387 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } 388 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } 389 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } 390 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } 391 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } 392 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } 393 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } 394 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } 395 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } 396 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } 397 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } 398 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } 399 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } 400 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } 401 | .ui-icon-arrow-4 { background-position: 0 -80px; } 402 | .ui-icon-arrow-4-diag { background-position: -16px -80px; } 403 | .ui-icon-extlink { background-position: -32px -80px; } 404 | .ui-icon-newwin { background-position: -48px -80px; } 405 | .ui-icon-refresh { background-position: -64px -80px; } 406 | .ui-icon-shuffle { background-position: -80px -80px; } 407 | .ui-icon-transfer-e-w { background-position: -96px -80px; } 408 | .ui-icon-transferthick-e-w { background-position: -112px -80px; } 409 | .ui-icon-folder-collapsed { background-position: 0 -96px; } 410 | .ui-icon-folder-open { background-position: -16px -96px; } 411 | .ui-icon-document { background-position: -32px -96px; } 412 | .ui-icon-document-b { background-position: -48px -96px; } 413 | .ui-icon-note { background-position: -64px -96px; } 414 | .ui-icon-mail-closed { background-position: -80px -96px; } 415 | .ui-icon-mail-open { background-position: -96px -96px; } 416 | .ui-icon-suitcase { background-position: -112px -96px; } 417 | .ui-icon-comment { background-position: -128px -96px; } 418 | .ui-icon-person { background-position: -144px -96px; } 419 | .ui-icon-print { background-position: -160px -96px; } 420 | .ui-icon-trash { background-position: -176px -96px; } 421 | .ui-icon-locked { background-position: -192px -96px; } 422 | .ui-icon-unlocked { background-position: -208px -96px; } 423 | .ui-icon-bookmark { background-position: -224px -96px; } 424 | .ui-icon-tag { background-position: -240px -96px; } 425 | .ui-icon-home { background-position: 0 -112px; } 426 | .ui-icon-flag { background-position: -16px -112px; } 427 | .ui-icon-calendar { background-position: -32px -112px; } 428 | .ui-icon-cart { background-position: -48px -112px; } 429 | .ui-icon-pencil { background-position: -64px -112px; } 430 | .ui-icon-clock { background-position: -80px -112px; } 431 | .ui-icon-disk { background-position: -96px -112px; } 432 | .ui-icon-calculator { background-position: -112px -112px; } 433 | .ui-icon-zoomin { background-position: -128px -112px; } 434 | .ui-icon-zoomout { background-position: -144px -112px; } 435 | .ui-icon-search { background-position: -160px -112px; } 436 | .ui-icon-wrench { background-position: -176px -112px; } 437 | .ui-icon-gear { background-position: -192px -112px; } 438 | .ui-icon-heart { background-position: -208px -112px; } 439 | .ui-icon-star { background-position: -224px -112px; } 440 | .ui-icon-link { background-position: -240px -112px; } 441 | .ui-icon-cancel { background-position: 0 -128px; } 442 | .ui-icon-plus { background-position: -16px -128px; } 443 | .ui-icon-plusthick { background-position: -32px -128px; } 444 | .ui-icon-minus { background-position: -48px -128px; } 445 | .ui-icon-minusthick { background-position: -64px -128px; } 446 | .ui-icon-close { background-position: -80px -128px; } 447 | .ui-icon-closethick { background-position: -96px -128px; } 448 | .ui-icon-key { background-position: -112px -128px; } 449 | .ui-icon-lightbulb { background-position: -128px -128px; } 450 | .ui-icon-scissors { background-position: -144px -128px; } 451 | .ui-icon-clipboard { background-position: -160px -128px; } 452 | .ui-icon-copy { background-position: -176px -128px; } 453 | .ui-icon-contact { background-position: -192px -128px; } 454 | .ui-icon-image { background-position: -208px -128px; } 455 | .ui-icon-video { background-position: -224px -128px; } 456 | .ui-icon-script { background-position: -240px -128px; } 457 | .ui-icon-alert { background-position: 0 -144px; } 458 | .ui-icon-info { background-position: -16px -144px; } 459 | .ui-icon-notice { background-position: -32px -144px; } 460 | .ui-icon-help { background-position: -48px -144px; } 461 | .ui-icon-check { background-position: -64px -144px; } 462 | .ui-icon-bullet { background-position: -80px -144px; } 463 | .ui-icon-radio-off { background-position: -96px -144px; } 464 | .ui-icon-radio-on { background-position: -112px -144px; } 465 | .ui-icon-pin-w { background-position: -128px -144px; } 466 | .ui-icon-pin-s { background-position: -144px -144px; } 467 | .ui-icon-play { background-position: 0 -160px; } 468 | .ui-icon-pause { background-position: -16px -160px; } 469 | .ui-icon-seek-next { background-position: -32px -160px; } 470 | .ui-icon-seek-prev { background-position: -48px -160px; } 471 | .ui-icon-seek-end { background-position: -64px -160px; } 472 | .ui-icon-seek-start { background-position: -80px -160px; } 473 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ 474 | .ui-icon-seek-first { background-position: -80px -160px; } 475 | .ui-icon-stop { background-position: -96px -160px; } 476 | .ui-icon-eject { background-position: -112px -160px; } 477 | .ui-icon-volume-off { background-position: -128px -160px; } 478 | .ui-icon-volume-on { background-position: -144px -160px; } 479 | .ui-icon-power { background-position: 0 -176px; } 480 | .ui-icon-signal-diag { background-position: -16px -176px; } 481 | .ui-icon-signal { background-position: -32px -176px; } 482 | .ui-icon-battery-0 { background-position: -48px -176px; } 483 | .ui-icon-battery-1 { background-position: -64px -176px; } 484 | .ui-icon-battery-2 { background-position: -80px -176px; } 485 | .ui-icon-battery-3 { background-position: -96px -176px; } 486 | .ui-icon-circle-plus { background-position: 0 -192px; } 487 | .ui-icon-circle-minus { background-position: -16px -192px; } 488 | .ui-icon-circle-close { background-position: -32px -192px; } 489 | .ui-icon-circle-triangle-e { background-position: -48px -192px; } 490 | .ui-icon-circle-triangle-s { background-position: -64px -192px; } 491 | .ui-icon-circle-triangle-w { background-position: -80px -192px; } 492 | .ui-icon-circle-triangle-n { background-position: -96px -192px; } 493 | .ui-icon-circle-arrow-e { background-position: -112px -192px; } 494 | .ui-icon-circle-arrow-s { background-position: -128px -192px; } 495 | .ui-icon-circle-arrow-w { background-position: -144px -192px; } 496 | .ui-icon-circle-arrow-n { background-position: -160px -192px; } 497 | .ui-icon-circle-zoomin { background-position: -176px -192px; } 498 | .ui-icon-circle-zoomout { background-position: -192px -192px; } 499 | .ui-icon-circle-check { background-position: -208px -192px; } 500 | .ui-icon-circlesmall-plus { background-position: 0 -208px; } 501 | .ui-icon-circlesmall-minus { background-position: -16px -208px; } 502 | .ui-icon-circlesmall-close { background-position: -32px -208px; } 503 | .ui-icon-squaresmall-plus { background-position: -48px -208px; } 504 | .ui-icon-squaresmall-minus { background-position: -64px -208px; } 505 | .ui-icon-squaresmall-close { background-position: -80px -208px; } 506 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } 507 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } 508 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } 509 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } 510 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } 511 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } 512 | 513 | 514 | /* Misc visuals 515 | ----------------------------------*/ 516 | 517 | /* Corner radius */ 518 | .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; } 519 | .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } 520 | .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } 521 | .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } 522 | .ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } 523 | .ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } 524 | .ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } 525 | .ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } 526 | .ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } 527 | 528 | /* Overlays */ 529 | .ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } 530 | .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } 531 | /* 532 | ColorBox Core Style: 533 | The following CSS is consistent between example themes and should not be altered. 534 | */ 535 | #colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;} 536 | #cboxOverlay{position:fixed; width:100%; height:100%;} 537 | #cboxMiddleLeft, #cboxBottomLeft{clear:left;} 538 | #cboxContent{position:relative;} 539 | #cboxLoadedContent{overflow:auto;} 540 | #cboxTitle{margin:0;} 541 | #cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;} 542 | #cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;} 543 | .cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none;} 544 | .cboxIframe{width:100%; height:100%; display:block; border:0;} 545 | #colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box;} 546 | 547 | /* 548 | User Style: 549 | Change the following styles to modify the appearance of ColorBox. They are 550 | ordered & tabbed in a way that represents the nesting of the generated HTML. 551 | */ 552 | #cboxOverlay{background:#000;} 553 | #colorbox{} 554 | #cboxTopLeft{width:14px; height:14px; background:url(colorbox/controls.png) no-repeat 0 0;} 555 | #cboxTopCenter{height:14px; background:url(colorbox/border.png) repeat-x top left;} 556 | #cboxTopRight{width:14px; height:14px; background:url(colorbox/controls.png) no-repeat -36px 0;} 557 | #cboxBottomLeft{width:14px; height:43px; background:url(colorbox/controls.png) no-repeat 0 -32px;} 558 | #cboxBottomCenter{height:43px; background:url(colorbox/border.png) repeat-x bottom left;} 559 | #cboxBottomRight{width:14px; height:43px; background:url(colorbox/controls.png) no-repeat -36px -32px;} 560 | #cboxMiddleLeft{width:14px; background:url(colorbox/controls.png) repeat-y -175px 0;} 561 | #cboxMiddleRight{width:14px; background:url(colorbox/controls.png) repeat-y -211px 0;} 562 | #cboxContent{background:#fff; overflow:visible;} 563 | .cboxIframe{background:#fff;} 564 | #cboxError{padding:50px; border:1px solid #ccc;} 565 | #cboxLoadedContent{margin-bottom:5px;} 566 | #cboxLoadingOverlay{background:url(colorbox/loading_background.png) no-repeat center center;} 567 | #cboxLoadingGraphic{background:url(colorbox/loading.gif) no-repeat center center;} 568 | #cboxTitle{position:absolute; bottom:-25px; left:0; text-align:center; width:100%; font-weight:bold; color:#7C7C7C;} 569 | #cboxCurrent{position:absolute; bottom:-25px; left:58px; font-weight:bold; color:#7C7C7C;} 570 | 571 | #cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{position:absolute; bottom:-29px; background:url(colorbox/controls.png) no-repeat 0px 0px; width:23px; height:23px; text-indent:-9999px;} 572 | #cboxPrevious{left:0px; background-position: -51px -25px;} 573 | #cboxPrevious:hover{background-position:-51px 0px;} 574 | #cboxNext{left:27px; background-position:-75px -25px;} 575 | #cboxNext:hover{background-position:-75px 0px;} 576 | #cboxClose{right:0; background-position:-100px -25px;} 577 | #cboxClose:hover{background-position:-100px 0px;} 578 | 579 | .cboxSlideshow_on #cboxSlideshow{background-position:-125px 0px; right:27px;} 580 | .cboxSlideshow_on #cboxSlideshow:hover{background-position:-150px 0px;} 581 | .cboxSlideshow_off #cboxSlideshow{background-position:-150px -25px; right:27px;} 582 | .cboxSlideshow_off #cboxSlideshow:hover{background-position:-125px 0px;} 583 | #loading { 584 | position: fixed; 585 | left: 40%; 586 | top: 50%; } 587 | 588 | a { 589 | color: #333333; 590 | text-decoration: none; } 591 | a:hover { 592 | color: black; 593 | text-decoration: underline; } 594 | 595 | body { 596 | font-family: "Lucida Grande", Helvetica, "Helvetica Neue", Arial, sans-serif; 597 | padding: 12px; 598 | background-color: #333333; } 599 | 600 | h1, h2, h3, h4 { 601 | color: #1c2324; 602 | margin: 0; 603 | padding: 0; 604 | margin-bottom: 12px; } 605 | 606 | table { 607 | width: 100%; } 608 | 609 | #content { 610 | clear: left; 611 | background-color: white; 612 | border: 2px solid #dddddd; 613 | border-top: 8px solid #dddddd; 614 | padding: 18px; 615 | -webkit-border-bottom-left-radius: 5px; 616 | -webkit-border-bottom-right-radius: 5px; 617 | -webkit-border-top-right-radius: 5px; 618 | -moz-border-radius-bottomleft: 5px; 619 | -moz-border-radius-bottomright: 5px; 620 | -moz-border-radius-topright: 5px; 621 | border-bottom-left-radius: 5px; 622 | border-bottom-right-radius: 5px; 623 | border-top-right-radius: 5px; } 624 | 625 | .dataTables_filter, .dataTables_info { 626 | padding: 2px 6px; } 627 | 628 | abbr.timeago { 629 | text-decoration: none; 630 | border: none; 631 | font-weight: bold; } 632 | 633 | .timestamp { 634 | float: right; 635 | color: #dddddd; } 636 | 637 | .group_tabs { 638 | list-style: none; 639 | float: left; 640 | margin: 0; 641 | padding: 0; } 642 | .group_tabs li { 643 | display: inline; 644 | float: left; } 645 | .group_tabs li a { 646 | font-family: Helvetica, Arial, sans-serif; 647 | display: block; 648 | float: left; 649 | text-decoration: none; 650 | padding: 4px 8px; 651 | background-color: #aaaaaa; 652 | background: -webkit-gradient(linear, 0 0, 0 bottom, from(#dddddd), to(#aaaaaa)); 653 | background: -moz-linear-gradient(#dddddd, #aaaaaa); 654 | background: linear-gradient(#dddddd, #aaaaaa); 655 | text-shadow: #e5e5e5 1px 1px 0px; 656 | border-bottom: none; 657 | color: #333333; 658 | font-weight: bold; 659 | margin-right: 8px; 660 | border-top: 1px solid #efefef; 661 | -webkit-border-top-left-radius: 2px; 662 | -webkit-border-top-right-radius: 2px; 663 | -moz-border-radius-topleft: 2px; 664 | -moz-border-radius-topright: 2px; 665 | border-top-left-radius: 2px; 666 | border-top-right-radius: 2px; } 667 | .group_tabs li a:hover { 668 | background-color: #cccccc; 669 | background: -webkit-gradient(linear, 0 0, 0 bottom, from(#eeeeee), to(#aaaaaa)); 670 | background: -moz-linear-gradient(#eeeeee, #aaaaaa); 671 | background: linear-gradient(#eeeeee, #aaaaaa); } 672 | .group_tabs li a:active { 673 | padding-top: 5px; 674 | padding-bottom: 3px; } 675 | .group_tabs li.active a { 676 | color: black; 677 | text-shadow: white 1px 1px 0px; 678 | background-color: #dddddd; 679 | background: -webkit-gradient(linear, 0 0, 0 bottom, from(white), to(#dddddd)); 680 | background: -moz-linear-gradient(white, #dddddd); 681 | background: linear-gradient(white, #dddddd); } 682 | 683 | .file_list { 684 | margin-bottom: 18px; } 685 | 686 | a.src_link { 687 | background: url("./magnify.png") no-repeat left 50%; 688 | padding-left: 18px; } 689 | 690 | tr, td { 691 | margin: 0; 692 | padding: 0; } 693 | 694 | th { 695 | white-space: nowrap; } 696 | th.ui-state-default { 697 | cursor: pointer; } 698 | th span.ui-icon { 699 | float: left; } 700 | 701 | td { 702 | padding: 4px 8px; } 703 | td.strong { 704 | font-weight: bold; } 705 | 706 | .source_table h3, .source_table h4 { 707 | padding: 0; 708 | margin: 0; 709 | margin-bottom: 4px; } 710 | .source_table .header { 711 | padding: 10px; } 712 | .source_table pre { 713 | margin: 0; 714 | padding: 0; 715 | white-space: normal; 716 | color: black; 717 | font-family: "Monaco", "Inconsolata", "Consolas", monospace; } 718 | .source_table code { 719 | color: black; 720 | font-family: "Monaco", "Inconsolata", "Consolas", monospace; } 721 | .source_table pre { 722 | background-color: #333333; } 723 | .source_table pre ol { 724 | margin: 0px; 725 | padding: 0px; 726 | margin-left: 45px; 727 | font-size: 12px; 728 | color: white; } 729 | .source_table pre li { 730 | margin: 0px; 731 | padding: 2px 6px; 732 | border-left: 5px solid white; } 733 | .source_table pre li code { 734 | white-space: pre; 735 | white-space: pre-wrap; } 736 | .source_table pre .hits { 737 | float: right; 738 | margin-left: 10px; 739 | padding: 2px 4px; 740 | background-color: #444444; 741 | background: -webkit-gradient(linear, 0 0, 0 bottom, from(#222222), to(#666666)); 742 | background: -moz-linear-gradient(#222222, #666666); 743 | background: linear-gradient(#222222, #666666); 744 | color: white; 745 | font-family: Helvetica, "Helvetica Neue", Arial, sans-serif; 746 | font-size: 10px; 747 | font-weight: bold; 748 | text-align: center; 749 | border-radius: 6px; } 750 | 751 | #footer { 752 | color: #dddddd; 753 | font-size: 12px; 754 | font-weight: bold; 755 | margin-top: 12px; 756 | text-align: right; } 757 | #footer a { 758 | color: #eeeeee; 759 | text-decoration: underline; } 760 | #footer a:hover { 761 | color: white; 762 | text-decoration: none; } 763 | 764 | .green { 765 | color: #009900; } 766 | 767 | .red { 768 | color: #990000; } 769 | 770 | .yellow { 771 | color: #ddaa00; } 772 | 773 | .source_table .covered { 774 | border-color: #009900; } 775 | .source_table .missed { 776 | border-color: #990000; } 777 | .source_table .never { 778 | border-color: black; } 779 | .source_table .skipped { 780 | border-color: #ffcc00; } 781 | .source_table .covered:nth-child(odd) { 782 | background-color: #cdf2cd; } 783 | .source_table .covered:nth-child(even) { 784 | background-color: #dbf2db; } 785 | .source_table .missed:nth-child(odd) { 786 | background-color: #f7c0c0; } 787 | .source_table .missed:nth-child(even) { 788 | background-color: #f7cfcf; } 789 | .source_table .never:nth-child(odd) { 790 | background-color: #efefef; } 791 | .source_table .never:nth-child(even) { 792 | background-color: #f4f4f4; } 793 | .source_table .skipped:nth-child(odd) { 794 | background-color: #fbf0c0; } 795 | .source_table .skipped:nth-child(even) { 796 | background-color: #fbffcf; } 797 | 798 | 799 | 800 | -------------------------------------------------------------------------------- /coverage/assets/0.10.0/colorbox/border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/colorbox/border.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/colorbox/controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/colorbox/controls.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/colorbox/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/colorbox/loading.gif -------------------------------------------------------------------------------- /coverage/assets/0.10.0/colorbox/loading_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/colorbox/loading_background.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/favicon_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/favicon_green.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/favicon_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/favicon_red.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/favicon_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/favicon_yellow.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/loading.gif -------------------------------------------------------------------------------- /coverage/assets/0.10.0/magnify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/magnify.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /coverage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage for App 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | loading 15 |
16 | 1043 | 1044 | 1045 | -------------------------------------------------------------------------------- /db/migrate/20160515174916_create_todos.rb: -------------------------------------------------------------------------------- 1 | class CreateTodos < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :todos do |t| 4 | t.string :title 5 | t.boolean :completed 6 | t.integer :order 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20160517090314_devise_token_auth_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseTokenAuthCreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table(:users) do |t| 4 | ## Required 5 | t.string :provider, :null => false, :default => "email" 6 | t.string :uid, :null => false, :default => "" 7 | 8 | ## Database authenticatable 9 | t.string :encrypted_password, :null => false, :default => "" 10 | 11 | ## Recoverable 12 | t.string :reset_password_token 13 | t.datetime :reset_password_sent_at 14 | 15 | ## Rememberable 16 | t.datetime :remember_created_at 17 | 18 | ## Trackable 19 | t.integer :sign_in_count, :default => 0, :null => false 20 | t.datetime :current_sign_in_at 21 | t.datetime :last_sign_in_at 22 | t.string :current_sign_in_ip 23 | t.string :last_sign_in_ip 24 | 25 | ## Confirmable 26 | t.string :confirmation_token 27 | t.datetime :confirmed_at 28 | t.datetime :confirmation_sent_at 29 | t.string :unconfirmed_email # Only if using reconfirmable 30 | 31 | ## Lockable 32 | # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts 33 | # t.string :unlock_token # Only if unlock strategy is :email or :both 34 | # t.datetime :locked_at 35 | 36 | ## User Info 37 | t.string :name 38 | t.string :nickname 39 | t.string :image 40 | t.string :email 41 | 42 | ## Roles 43 | t.boolean :admin 44 | 45 | ## Tokens 46 | t.text :tokens 47 | 48 | t.timestamps 49 | end 50 | 51 | add_index :users, :email 52 | add_index :users, [:uid, :provider], :unique => true 53 | add_index :users, :reset_password_token, :unique => true 54 | # add_index :users, :confirmation_token, :unique => true 55 | # add_index :users, :unlock_token, :unique => true 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your 6 | # database schema. If you need to create the application database on another 7 | # system, you should be using db:schema:load, not running all the migrations 8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 9 | # you'll amass, the slower it'll run and the greater likelihood for issues). 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(version: 20160517090314) do 14 | 15 | # These are extensions that must be enabled in order to support this database 16 | enable_extension "plpgsql" 17 | 18 | create_table "todos", force: :cascade do |t| 19 | t.string "title" 20 | t.boolean "completed" 21 | t.integer "order" 22 | t.datetime "created_at", null: false 23 | t.datetime "updated_at", null: false 24 | end 25 | 26 | create_table "users", force: :cascade do |t| 27 | t.string "provider", default: "email", null: false 28 | t.string "uid", default: "", null: false 29 | t.string "encrypted_password", default: "", null: false 30 | t.string "reset_password_token" 31 | t.datetime "reset_password_sent_at" 32 | t.datetime "remember_created_at" 33 | t.integer "sign_in_count", default: 0, null: false 34 | t.datetime "current_sign_in_at" 35 | t.datetime "last_sign_in_at" 36 | t.string "current_sign_in_ip" 37 | t.string "last_sign_in_ip" 38 | t.string "confirmation_token" 39 | t.datetime "confirmed_at" 40 | t.datetime "confirmation_sent_at" 41 | t.string "unconfirmed_email" 42 | t.string "name" 43 | t.string "nickname" 44 | t.string "image" 45 | t.string "email" 46 | t.boolean "admin" 47 | t.text "tokens" 48 | t.datetime "created_at" 49 | t.datetime "updated_at" 50 | t.index ["email"], name: "index_users_on_email", using: :btree 51 | t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree 52 | t.index ["uid", "provider"], name: "index_users_on_uid_and_provider", unique: true, using: :btree 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /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 rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) 7 | # Character.create(name: 'Luke', movie: movies.first) 8 | 9 | 100.times do |number| 10 | User.create(:email => "test_#{number}@example.com", :password => 'examplPass123', :password_confirmation => 'examplPass123') 11 | end -------------------------------------------------------------------------------- /doc/api.raml: -------------------------------------------------------------------------------- 1 | #%RAML 1.0 2 | title: New API 3 | version: v1 4 | protocols: [ HTTP, HTTPS ] 5 | baseUri: https://api.starterkit.hawatel.com 6 | mediaType: application/json 7 | /auth: 8 | get: 9 | responses: 10 | 200: 11 | body: 12 | application/json: 13 | example: | 14 | { 15 | "message" : "Hello World" 16 | } 17 | post: 18 | description: "Create new user" 19 | body: 20 | application/json: 21 | schema: !include schemas/auth/post.request.json 22 | example: | 23 | { 24 | "id": 123233, 25 | "name": "example" 26 | } 27 | responses: 28 | 200: 29 | body: 30 | application/json: 31 | example: | 32 | { 33 | "message" : "Hello World" 34 | } 35 | -------------------------------------------------------------------------------- /doc/schemas/auth/post.request.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/hyper-schema", 3 | "title": "FIXME - Auth", 4 | "description": "FIXME", 5 | "stability": "prototype", 6 | "strictProperties": true, 7 | "type": [ 8 | "object" 9 | ], 10 | "properties": { 11 | "id": { 12 | "description": "unique identifier of auth", 13 | "readOnly": true, 14 | "type": [ 15 | "integer" 16 | ] 17 | }, 18 | "email": { 19 | "description": "unique name of auth", 20 | "type": [ 21 | "string" 22 | ] 23 | }, 24 | "password": { 25 | "description": "password for user", 26 | "type": [ 27 | "string" 28 | ] 29 | }, 30 | "password_confirmation": { 31 | "description": "confirm password for user", 32 | "type": [ 33 | "string" 34 | ] 35 | }, 36 | "created_at": { 37 | "description": "when auth was created", 38 | "format": "date-time", 39 | "type": [ 40 | "string" 41 | ] 42 | }, 43 | "updated_at": { 44 | "description": "when auth was updated", 45 | "format": "date-time", 46 | "type": [ 47 | "string" 48 | ] 49 | } 50 | }, 51 | "required": ["email", "password", "password_confirmation"] 52 | } 53 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | web: 4 | environment: 5 | - REDIS_URL=redis://redis:6379 6 | build: . 7 | command: bin/rails server --port 3000 --binding 0.0.0.0 8 | ports: 9 | - "3000:3000" 10 | volumes: 11 | - .:/app 12 | volumes_from: 13 | - bundle 14 | links: 15 | - redis 16 | - postgres 17 | depends_on: 18 | - redis 19 | 20 | postgres: 21 | image: postgres:9.4 22 | environment: 23 | - POSTGRES_PASSWORD=SecurePasswordPG 24 | ports: 25 | - "5432:5432" 26 | volumes: 27 | - /tmp/rails5apistarter/postgresql:/var/lib/postgresql/data 28 | 29 | redis: 30 | image: redis 31 | command: redis-server /app/config/redis.conf 32 | volumes: 33 | - .:/app 34 | ports: 35 | - "6379" 36 | 37 | sidekiq: 38 | image: rails5apistarter_web 39 | environment: 40 | - REDIS_URL=redis://redis:6379/12 41 | links: 42 | - redis 43 | - postgres 44 | depends_on: 45 | - redis 46 | volumes: 47 | - '.:/app' 48 | volumes_from: 49 | - bundle 50 | command: sidekiq -c 25 -q default 51 | 52 | bundle: 53 | image: rails5apistarter_web 54 | volumes: 55 | - /tmp/bundle:/bundle 56 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/tasks/docs_generate.rake: -------------------------------------------------------------------------------- 1 | require 'rspec/core/rake_task' 2 | 3 | desc 'Run API specs test in spec/requests' 4 | RSpec::Core::RakeTask.new('spec:docs') do |t| 5 | t.pattern = 'spec/requests/**/*_spec.rb' 6 | t.rspec_opts = ["--format RspecApiDocumentation::ApiFormatter"] 7 | end -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/log/.keep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.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 | -------------------------------------------------------------------------------- /spec/acceptance/auth_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | require 'rspec_api_documentation/dsl' 3 | require 'factory_girl' 4 | 5 | RspecApiDocumentation.configure do |config| 6 | config.format = [:json, :combined_text, :html] 7 | config.curl_host = 'http://localhost:3000' 8 | end 9 | 10 | resource "Authentication" do 11 | 12 | before(:each) do 13 | @user = FactoryGirl.build(:user) 14 | @user.create_new_auth_token 15 | end 16 | 17 | post "/auth/sign_in" do 18 | parameter :email, 'Email address' 19 | parameter :password, 'Password for user' 20 | 21 | it "incorrect login and password" do 22 | do_request(:email => 'user@dontexistr.com', :password => 'wrong_password') 23 | expect(status).to eq(401) 24 | expect(response_body).to include('Invalid login credentials') 25 | end 26 | 27 | it "user dosn't confirm registration process" do 28 | do_request(:email => @user.email, :password => @user.password) # send post data 29 | expect(status).to eq(401) 30 | expect(response_body).to include('A confirmation email was sent to your account at') 31 | end 32 | 33 | it "correct login and password" do 34 | @user.skip_confirmation! 35 | @user.save! 36 | do_request(:email => @user.email, :password => @user.password) 37 | expect(status).to eq(200) 38 | expect(response_body).to include(@user.email) 39 | end 40 | end 41 | 42 | 43 | post "/auth/" do 44 | parameter :email, 'Email address' 45 | parameter :password, 'User password' 46 | parameter :password_confirmation, 'Confirmation password' 47 | parameter :confirm_success_url, 'Redirect URL' 48 | 49 | it "user already exist" do 50 | do_request(:email => @user.email, :password => @user.password, :password_confirmation => @user.password, :confirm_success_url => 'localhost:3000') 51 | expect(status).to eq(422) 52 | expect(response_body).to include('Email already in use') 53 | end 54 | 55 | it "create new user" do 56 | @user = FactoryGirl.build(:user) 57 | do_request(:email => @user.email, :password => @user.password, :password_confirmation => @user.password, :confirm_success_url => 'localhost:3000') 58 | expect(status).to eq(200) 59 | expect(response_body).to include(@user.email) 60 | end 61 | end 62 | 63 | 64 | delete '/auth/sign_out' do 65 | it "logout current logged user" do 66 | user = FactoryGirl.build(:user) 67 | set_header(user.create_new_auth_token) 68 | do_request 69 | expect(status).to eq(200) 70 | end 71 | end 72 | 73 | end 74 | 75 | # Before each call, set key value to header. Required by auth 76 | def set_header(auth_headers) 77 | header 'access-token', auth_headers['access-token'] 78 | header 'token-type', auth_headers['token-type'] 79 | header 'client', auth_headers['client'] 80 | header 'expiry', auth_headers['expiry'] 81 | header 'uid', auth_headers['uid'] 82 | end -------------------------------------------------------------------------------- /spec/acceptance/todos_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | require 'rspec_api_documentation/dsl' 3 | require 'factory_girl' 4 | 5 | 6 | RspecApiDocumentation.configure do |config| 7 | config.format = [:json, :combined_text, :html] 8 | config.curl_host = 'http://localhost:3000' 9 | config.api_name = "Example App API" 10 | end 11 | 12 | resource "TODO" do 13 | 14 | before do 15 | # create fake element in TODOs list 16 | Todo.create(:title => 'This is Fake data which is put to TO', ) 17 | end 18 | 19 | before (:each) do 20 | # create fake user 21 | user = FactoryGirl.build(:user) 22 | set_header(user.create_new_auth_token) 23 | end 24 | 25 | # GET /todos 26 | get "/todos.json" do 27 | parameter :parameter1, "The thing you want to greet" 28 | parameter :parameter2, "The thing you want to greet" 29 | 30 | it "Name showed on index page" do 31 | explanation "This is example comment which is added to documentation" 32 | do_request 33 | expect(response_headers["Content-Type"]).to eq("application/json; charset=utf-8") 34 | expect(status).to eq(200) 35 | expect(response_body).to include('success') 36 | end 37 | end 38 | 39 | end 40 | 41 | # Before each call, set key value to header. Required by auth 42 | def set_header(auth_headers) 43 | header 'access-token', auth_headers['access-token'] 44 | header 'token-type', auth_headers['token-type'] 45 | header 'client', auth_headers['client'] 46 | header 'expiry', auth_headers['expiry'] 47 | header 'uid', auth_headers['uid'] 48 | end -------------------------------------------------------------------------------- /spec/controllers/todos_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | # This spec was generated by rspec-rails when you ran the scaffold generator. 4 | # It demonstrates how one might use RSpec to specify the controller code that 5 | # was generated by Rails when you ran the scaffold generator. 6 | # 7 | # It assumes that the implementation code is generated by the rails scaffold 8 | # generator. If you are using any extension libraries to generate different 9 | # controller code, this generated spec may or may not pass. 10 | # 11 | # It only uses APIs available in rails and/or rspec-rails. There are a number 12 | # of tools you can use to make these specs even more expressive, but we're 13 | # sticking to rails and rspec-rails APIs to keep things simple and stable. 14 | # 15 | # Compared to earlier versions of this generator, there is very limited use of 16 | # stubs and message expectations in this spec. Stubs are only used when there 17 | # is no simpler way to get a handle on the object needed for the example. 18 | # Message expectations are only used when there is no simpler way to specify 19 | # that an instance is receiving a specific message. 20 | 21 | RSpec.describe TodosController, :type => :controller do 22 | 23 | # This should return the minimal set of attributes required to create a valid 24 | # Todo. As you add validations to Todo, be sure to 25 | # adjust the attributes here as well. 26 | let(:valid_attributes) { 27 | skip("Add a hash of attributes valid for your model") 28 | } 29 | 30 | let(:invalid_attributes) { 31 | skip("Add a hash of attributes invalid for your model") 32 | } 33 | 34 | # This should return the minimal set of values that should be in the session 35 | # in order to pass any filters (e.g. authentication) defined in 36 | # TodosController. Be sure to keep this updated too. 37 | let(:valid_session) { {} } 38 | 39 | describe "GET index" do 40 | it "assigns all todos as @todos" do 41 | todo = Todo.create! valid_attributes 42 | get :public, {}, valid_session 43 | expect(assigns(:todos)).to eq([todo]) 44 | end 45 | end 46 | 47 | describe "GET show" do 48 | it "assigns the requested todo as @todo" do 49 | todo = Todo.create! valid_attributes 50 | get :show, {:id => todo.to_param}, valid_session 51 | expect(assigns(:todo)).to eq(todo) 52 | end 53 | end 54 | 55 | 56 | describe "GET edit" do 57 | it "assigns the requested todo as @todo" do 58 | todo = Todo.create! valid_attributes 59 | get :edit, {:id => todo.to_param}, valid_session 60 | expect(assigns(:todo)).to eq(todo) 61 | end 62 | end 63 | 64 | describe "POST create" do 65 | describe "with valid params" do 66 | it "creates a new Todo" do 67 | expect { 68 | post :create, {:todo => valid_attributes}, valid_session 69 | }.to change(Todo, :count).by(1) 70 | end 71 | 72 | it "assigns a newly created todo as @todo" do 73 | post :create, {:todo => valid_attributes}, valid_session 74 | expect(assigns(:todo)).to be_a(Todo) 75 | expect(assigns(:todo)).to be_persisted 76 | end 77 | 78 | it "redirects to the created todo" do 79 | post :create, {:todo => valid_attributes}, valid_session 80 | expect(response).to redirect_to(Todo.last) 81 | end 82 | end 83 | 84 | describe "with invalid params" do 85 | it "assigns a newly created but unsaved todo as @todo" do 86 | post :create, {:todo => invalid_attributes}, valid_session 87 | expect(assigns(:todo)).to be_a_new(Todo) 88 | end 89 | 90 | it "re-renders the 'new' template" do 91 | post :create, {:todo => invalid_attributes}, valid_session 92 | expect(response).to render_template("new") 93 | end 94 | end 95 | end 96 | 97 | describe "PUT update" do 98 | describe "with valid params" do 99 | let(:new_attributes) { 100 | skip("Add a hash of attributes valid for your model") 101 | } 102 | 103 | it "updates the requested todo" do 104 | todo = Todo.create! valid_attributes 105 | put :update, {:id => todo.to_param, :todo => new_attributes}, valid_session 106 | todo.reload 107 | skip("Add assertions for updated state") 108 | end 109 | 110 | it "assigns the requested todo as @todo" do 111 | todo = Todo.create! valid_attributes 112 | put :update, {:id => todo.to_param, :todo => valid_attributes}, valid_session 113 | expect(assigns(:todo)).to eq(todo) 114 | end 115 | 116 | it "redirects to the todo" do 117 | todo = Todo.create! valid_attributes 118 | put :update, {:id => todo.to_param, :todo => valid_attributes}, valid_session 119 | expect(response).to redirect_to(todo) 120 | end 121 | end 122 | 123 | describe "with invalid params" do 124 | it "assigns the todo as @todo" do 125 | todo = Todo.create! valid_attributes 126 | put :update, {:id => todo.to_param, :todo => invalid_attributes}, valid_session 127 | expect(assigns(:todo)).to eq(todo) 128 | end 129 | 130 | it "re-renders the 'edit' template" do 131 | todo = Todo.create! valid_attributes 132 | put :update, {:id => todo.to_param, :todo => invalid_attributes}, valid_session 133 | expect(response).to render_template("edit") 134 | end 135 | end 136 | end 137 | 138 | describe "DELETE destroy" do 139 | it "destroys the requested todo" do 140 | todo = Todo.create! valid_attributes 141 | expect { 142 | delete :destroy, {:id => todo.to_param}, valid_session 143 | }.to change(Todo, :count).by(-1) 144 | end 145 | 146 | it "redirects to the todos list" do 147 | todo = Todo.create! valid_attributes 148 | delete :destroy, {:id => todo.to_param}, valid_session 149 | expect(response).to redirect_to(todos_url) 150 | end 151 | end 152 | 153 | end 154 | -------------------------------------------------------------------------------- /spec/factories/todos.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :todo do 3 | title "MyString" 4 | completed false 5 | order 1 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/factories/user.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :user do 3 | name "RSpec Account" 4 | email { Faker::Internet.email } 5 | password "abc123456" 6 | password_confirmation "abc123456" 7 | end 8 | end -------------------------------------------------------------------------------- /spec/models/todo_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Todo, :type => :model do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV["RAILS_ENV"] ||= 'test' 3 | require 'spec_helper' 4 | require File.expand_path("../../config/environment", __FILE__) 5 | require 'rspec/rails' 6 | require 'devise' 7 | require 'factory_girl_rails' 8 | require 'simplecov' 9 | SimpleCov.start 10 | 11 | # Load external settings 12 | require 'support/settings/rspec_api_documentation' 13 | 14 | 15 | # Add additional requires below this line. Rails is not loaded until this point! 16 | 17 | # Requires supporting ruby files with custom matchers and macros, etc, in 18 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 19 | # run as spec files by default. This means that files in spec/support that end 20 | # in _spec.rb will both be required and run as specs, causing the specs to be 21 | # run twice. It is recommended that you do not name files matching this glob to 22 | # end with _spec.rb. You can configure this pattern with the --pattern 23 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 24 | # 25 | # The following line is provided for convenience purposes. It has the downside 26 | # of increasing the boot-up time by auto-requiring all files in the support 27 | # directory. Alternatively, in the individual `*_spec.rb` files, manually 28 | # require only the support files necessary. 29 | # 30 | # Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } 31 | 32 | # Checks for pending migrations before tests are run. 33 | # If you are not using ActiveRecord, you can remove this line. 34 | ActiveRecord::Migration.maintain_test_schema! 35 | 36 | RSpec.configure do |config| 37 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 38 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 39 | 40 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 41 | # examples within a transaction, remove the following line or assign false 42 | # instead of true. 43 | config.use_transactional_fixtures = true 44 | 45 | # Include JSON helper. 46 | # https://github.com/collectiveidea/json_spec 47 | config.include JsonSpec::Helpers 48 | 49 | # RSpec Rails can automatically mix in different behaviours to your tests 50 | # based on their file location, for example enabling you to call `get` and 51 | # `post` in specs under `spec/controllers`. 52 | # 53 | # You can disable this behaviour by removing the line below, and instead 54 | # explicitly tag your specs with their type, e.g.: 55 | # 56 | # RSpec.describe UsersController, :type => :controller do 57 | # # ... 58 | # end 59 | # 60 | # The different available types are documented in the features, such as in 61 | # https://relishapp.com/rspec/rspec-rails/docs 62 | config.infer_spec_type_from_file_location! 63 | 64 | # Devise 65 | config.include Devise::TestHelpers, type: :controller 66 | config.include FactoryGirl::Syntax::Methods 67 | 68 | end 69 | -------------------------------------------------------------------------------- /spec/routing/todos_routing_spec.rb: -------------------------------------------------------------------------------- 1 | require "rails_helper" 2 | 3 | RSpec.describe TodosController, :type => :routing do 4 | describe "routing" do 5 | 6 | it "routes to #index" do 7 | expect(:get => "/todos").to route_to(:format=>"json", :controller=>"todos", :action=>"index") 8 | end 9 | 10 | it "routes to #new" do 11 | expect(:get => "/todos/new").to route_to(:format=>"json", :controller=>"todos", :action=>"show", :id=>"new") 12 | end 13 | 14 | it "routes to #show" do 15 | expect(:get => "/todos/1").to route_to(:format=>"json", :controller=>"todos", :action=>"show", :id=>"1") 16 | end 17 | 18 | it "routes to #create" do 19 | expect(:post => "/todos").to route_to(:format=>"json", :controller=>"todos", :action=>"create") 20 | end 21 | 22 | it "routes to #update" do 23 | expect(:put => "/todos/1").to route_to(:format=>"json", :controller=>"todos", :action=>"update", :id=>"1") 24 | end 25 | 26 | it "routes to #destroy" do 27 | expect(:delete => "/todos/1").to route_to(:format=>"json", :controller=>"todos", :action=>"destroy", :id=>"1") 28 | end 29 | 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause this 4 | # file to always be loaded, without a need to explicitly require it in any files. 5 | # 6 | # Given that it is always loaded, you are encouraged to keep this file as 7 | # light-weight as possible. Requiring heavyweight dependencies from this file 8 | # will add to the boot time of your test suite on EVERY test run, even for an 9 | # individual file that may not need all of that loaded. Instead, consider making 10 | # a separate helper file that requires the additional dependencies and performs 11 | # the additional setup, and require it from the spec files that actually need it. 12 | # 13 | # The `.rspec` file also contains a few flags that are not defaults but that 14 | # users commonly want. 15 | # 16 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 17 | # 18 | RSpec.configure do |config| 19 | # rspec-expectations config goes here. You can use an alternate 20 | # assertion/expectation library such as wrong or the stdlib/minitest 21 | # assertions if you prefer. 22 | config.expect_with :rspec do |expectations| 23 | # This option will default to `true` in RSpec 4. It makes the `description` 24 | # and `failure_message` of custom matchers include text for helper methods 25 | # defined using `chain`, e.g.: 26 | # be_bigger_than(2).and_smaller_than(4).description 27 | # # => "be bigger than 2 and smaller than 4" 28 | # ...rather than: 29 | # # => "be bigger than 2" 30 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 31 | end 32 | 33 | # rspec-mocks config goes here. You can use an alternate test double 34 | # library (such as bogus or mocha) by changing the `mock_with` option here. 35 | config.mock_with :rspec do |mocks| 36 | # Prevents you from mocking or stubbing a method that does not exist on 37 | # a real object. This is generally recommended, and will default to 38 | # `true` in RSpec 4. 39 | mocks.verify_partial_doubles = true 40 | end 41 | 42 | # The settings below are suggested to provide a good initial experience 43 | # with RSpec, but feel free to customize to your heart's content. 44 | =begin 45 | # These two settings work together to allow you to limit a spec run 46 | # to individual examples or groups you care about by tagging them with 47 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 48 | # get run. 49 | config.filter_run :focus 50 | config.run_all_when_everything_filtered = true 51 | 52 | # Limits the available syntax to the non-monkey patched syntax that is recommended. 53 | # For more details, see: 54 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 55 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 56 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 57 | config.disable_monkey_patching! 58 | 59 | # Many RSpec users commonly either run the entire suite or an individual 60 | # file, and it's useful to allow more verbose output when running an 61 | # individual spec file. 62 | if config.files_to_run.one? 63 | # Use the documentation formatter for detailed output, 64 | # unless a formatter has already been configured 65 | # (e.g. via a command-line flag). 66 | config.default_formatter = 'doc' 67 | end 68 | 69 | # Print the 10 slowest examples and example groups at the 70 | # end of the spec run, to help surface which specs are running 71 | # particularly slow. 72 | config.profile_examples = 10 73 | 74 | # Run specs in random order to surface order dependencies. If you find an 75 | # order dependency and want to debug it, you can fix the order by providing 76 | # the seed, which is printed after each run. 77 | # --seed 1234 78 | config.order = :random 79 | 80 | # Seed global randomization in this process using the `--seed` CLI option. 81 | # Setting this allows you to use `--seed` to deterministically reproduce 82 | # test failures related to randomization by passing the same `--seed` value 83 | # as the one that triggered the failure. 84 | Kernel.srand config.seed 85 | =end 86 | end 87 | -------------------------------------------------------------------------------- /spec/support/settings/rspec_api_documentation.rb: -------------------------------------------------------------------------------- 1 | RspecApiDocumentation.configure do |config| 2 | # Output folder 3 | config.docs_dir = Rails.root.join("doc", "spec_documentation") 4 | 5 | # Output format 6 | config.format = [:html] 7 | 8 | # Change the name of the API on index pages 9 | config.api_name = "API Documentation" 10 | end 11 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hawatel/rails5-api-starter/abd21c252aa844be9d5abe8418b12ab40bb1f9d9/tmp/.keep --------------------------------------------------------------------------------