diff --git a/.gitignore b/.gitignore index e492f373..6c2dc11a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ tmp *.a mkmf.log *.tmp +.rspec_status ########################################################## ########################################################## diff --git a/.rspec b/.rspec new file mode 100644 index 00000000..bd5e0288 --- /dev/null +++ b/.rspec @@ -0,0 +1,3 @@ +--format progress +--color +--require spec_helper diff --git a/.travis.yml b/.travis.yml index 87fc2cde..176e6626 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ +language: ruby rvm: - 2.2.4 - - 2.3.2 - - 2.4.0 + - 2.3.7 + - 2.4.4 + - 2.5.1 - ruby-head diff --git a/Gemfile b/Gemfile index 37fcd5b7..a7f9b326 100644 --- a/Gemfile +++ b/Gemfile @@ -10,4 +10,7 @@ group :test do gem 'coveralls', require: false end +# => Required for Windows +gem 'tzinfo-data' if Gem.win_platform? # => TZInfo For Windows + ########################################### diff --git a/README.md b/README.md index 741a559c..13192c51 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ +![Exception Handler](readme/title.jpg "Exception Handler Logo") +

- New README coming soon (with upgrade to underlying codebase). +

-![Exception Handler](readme/title.jpg "Exception Handler Logo") +

+ +

- Custom 404 & 500 production error pages for Rails 4 & 5. + ➡️ ExceptionHandler is a Custom Error Pages Gem For Ruby on Rails ⬅️ - With 160,000+ downloads, it is one of the most
popular, robust & extensible exceptions management gems for Ruby on Rails 4 & 5+...

@@ -18,132 +22,227 @@

- InstallSetupSupport + +

---- -

-
+ Version 🏹 0.8.0.0 🏹 has now introduced a number of ⭐️ KEY UPGRADES ⭐️ including...
🚧 New Config Settings 🚧 ▪️ 💻 Custom Views Options 💻 ▪️ 💬 4xx/5xx Locales 💬...

-   Responsive   -   Branded Error Pages   -   Middleware Exception Handling   -   Fully Customizable   + +

- - + + ⚠️ Tutorial shows how it works ⚠️ +
✉️ Support Email ✉️ +

---- + + +

- +

---- -

- +   Responsive   +   Branded Error Pages   +   Middleware Exception Handling   +   Fully Customizable  

-   New Controller   -   New Middleware   -   Full Test Suite   -   Fully Rails 4 & 5 Compatible   + +

-Brand new `controller` & `middleware` have made **`ExceptionHandler`** even more powerful & efficient. Now you can use `ExceptionHandler` with a [single click](#install) → **plug and play** custom exception pages: + +
+

+

+

⌚️ Introduction ⌚️

+

+

+
+ +➡️ [**`ExceptionHandler`**](https://rubygems.org/gems/exception_handler) ⬅️ was designed to replace Rails' error pages ([`400.html`, `422.html`, `500.html`](https://github.com/rails/rails/tree/ef0b05e78fb0b928c7ef48d3c365dc849af50305/railties/lib/rails/generators/rails/app/templates/public)) with dynamic views...

-
- - +

-

For over 3 years, ExceptionHandler has provided production-level Rails exception handling for 4xx and 5xx errors:

+The gem inserts a custom [ `controller`](app/controllers/exception_handler/exceptions_controller.rb) into [`exceptions_app`](http://guides.rubyonrails.org/configuring.html#rails-general-configuration), allowing us to render custom HTML for erroneous requests. -![HTTP Error Codes][http_codes] +The controller uses a *single* method/view to build a response to errors. This view remains the same for *every* exception; the ONLY change is the *[layout](/app/views/layouts/exception.html.erb)* - depending on the HTTP response being returned (`4xx`/`5xx`). -Since **browsers only read `4xx` & `5xx` error codes**, all Rails exceptions have to be inferred. Thus, `ExceptionHandler` simply has to manage how the `4xx` / `5xx` errors are passed to the browser. +The beauty lies in the *simplicity* through which this is achieved → rather than having many different elements, its SOLE focus is to provide different HTML responses via differing *layouts*. `ExceptionHandler` does this within the scope of [`ActionView`](http://guides.rubyonrails.org/action_view_overview.html), allowing for the use of `views`, `helpers` and `data` from the database. -Unlike other gems, **`ExceptionHandler` uses a custom [`controller`](app/controllers/exception_handler/exceptions_controller.rb) to build an [`@exception`](app/models/exception_handler/exception.rb) object**. This allows us to save the exception, email it or do anything else we may need. The gem has already been a massive success and we continue to actively maintain it. +Gem works 100% out of the box in `production`, and has the option to be called in [`dev`](#dev) if necessary. -Now you can try for yourself ... +-- +### 📑 HTTP ----- +The most important thing to understand is that *it doesn't matter* which errors Ruby/Rails raises - they *all* need to be wrapped in a [valid HTTP response](https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html). Due to the nature of HTTP, you only need to facilitate responses for [`4xx`](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors) - [`5xx`](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_errors). -

-
- -

- -The secret lies in [**`config.exceptions_app`**][exception_app] ↴ +This means that all you're really doing is taking "Ruby" errors and giving them an appropriate [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) & [message body](https://en.wikipedia.org/wiki/HTTP_message_body) (HTML). Rails handles the process for you - the *only* thing we need to worry about is how the HTML is generated. -> **`config.exceptions_app`** sets the exceptions application invoked by the **`ShowException`** middleware when an exception happens. Defaults to **`ActionDispatch::PublicExceptions.new(Rails.public_path)`** +What confuses most is the way in which Rails does this. The process is handled by [`ActionDispatch::ShowExceptions`](https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L44) - which builds a new response out of the one passed to it by the exception generator. Through this process, it calls whichever class is present in [`exceptions_app`](http://guides.rubyonrails.org/configuring.html#rails-general-configuration)... -![Exceptions handled by the ActiveDispatch::ShowExceptions Middleware][middleware] + # show_exceptions.rb + def render_exception(request, exception) + backtrace_cleaner = request.get_header "action_dispatch.backtrace_cleaner" + wrapper = ExceptionWrapper.new(backtrace_cleaner, exception) + status = wrapper.status_code + request.set_header "action_dispatch.exception", wrapper.exception + request.set_header "action_dispatch.original_path", request.path_info + request.path_info = "/#{status}" + response = @exceptions_app.call(request.env) #-> this is where the HTML is generated + response[1]["X-Cascade"] == "pass" ? pass_response(status) : response + rescue Exception => failsafe_error + $stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}" + FAILSAFE_RESPONSE + end -Each time an exception is raised, [`ShowExceptions`][show_exception] takes the request and forwards it to `config.exceptions_app`. This is expected to return a response - allowing us to inject a [`controller`](app/controllers/exception_handler/exceptions_controller.rb): +In other words, what a user *sees* has very little to do with the fact Rails experienced an error. `ExceptionHandler` doesn't change this behaviour - it simply adds our own controller/views setup to provide the HTML... -![config.exceptions_app - The key to all Rails exceptions][exceptions_app] +

+ +

-Because our callback maintains the request, we are able to do whatever we need before serving a response. This is a **major** advantage over the "default" (routes). The routes invokes Rails twice and does not persist the request. +To better explain, there are **5️⃣ types of HTTP status code** - [`10x`][10x], [`20x`][20x], [`30x`][30x], [`40x`][40x], & [`50x`][50x]. - **`ExceptionHandler` is the only gem to provide middleware-powered exception handling.** It populates our custom `view` with details, giving us the ability to **maintain branding** when exceptions are raised: +Each does its own thing, but what's important is they *ALL* describe "responses" that your web browser will receive for HTTP requests. The only *erroneous* status codes are `4xx` (client error) or `5xx` (server error)... -![Exceptions handled by the ActiveDispatch::ShowExceptions Middleware][middleware] +

+ +

-**`ExceptionHandler` is the most EFFECTIVE and EFFICIENT gem to handle exceptions in Rails**. +The point is that when you're dealing with "errors" online, you're *actually* dealing with erroneous **HTTP STATUS CODES**. The response delivered with these codes is *ALWAYS* going to remain the same; difference lying in how they're built (on the server). -Once invoked, its `model`, `controller` and `views` work together to serve the best responses to Rails errors ... +By default, `NGinx` + `Apache` use "static" HTML pages to show the errors - if we're using Rails, we have the ability to create *our own* pages. This is exactly what our gem has been designed to do. ----------- +**`ExceptionHandler`** provides Rails with the ability to serve ***dynamic*** exception pages, built with **your *own*** layouts/views. By overriding the `exceptions_app` hook, it provides a custom `controller`, `model` and `views` to display custom error pages. -

-
- -
- Custom Rails Error Pages - ZERO configuration needed: -
-

+The system is 100% compatible with Rails 4 & 5 and has already been downloaded **180,000+** times...

- + +

+ +
+

+

🔨 Setup 🔨

+

--
The most important thing to appreciate about the gem is that it's designed to be completely unobtrusive.

+

This means that if you're looking at using it,

+

+

+

+ Configuration Options Config    Dev Dev    Database Database    Email Email    Views Views    Locales Locales    Custom Exceptions Custom Exceptions    Generators Generators +

+

+
-

- You can install it from the CLI or Gemfile - it will AUTOMATICALLY run in production. -
- ↓ To run in development, use dev mode -

+ +

+

🚧 Config 🚧

+

---- +**The ONLY thing you need to configure `ExceptionHandler` is the [`config`](https://github.com/richpeck/exception_handler/blob/master/lib/exception_handler/config.rb)**. -

- If you want to set it up your way, you can use these features... -

+Whilst the gem **works out of the box** (without any configuration), if you want to manage the [`layouts`](#layouts), [`email`](#email), [`dev`](#dev) or the [`database`](#db), you'll need to set the appropriate values in the config hash ([invoked at init](https://github.com/richpeck/exception_handler/blob/master/lib/exception_handler/engine.rb#L44)). -

- Cinfiguration Options Config    Dev Dev    Database Database    Email Email    Views Views    Locales Locales    Custom Exceptions Custom Exceptions    Generators Generators -

+This can be done in `config/application.rb` or `config/environments/[env].rb` ↴ ----- +``` +# config/application.rb + +module YourApp + class Application < Rails::Application + + # => This is an example of ALL available config options + # => You're able to see exactly how it works here: + # => https://github.com/richpeck/exception_handler/blob/master/lib/exception_handler/config.rb -## Config + # => Config hash (no initializer required) + config.exception_handler = { + dev: nil, # allows you to turn ExceptionHandler "on" in development + db: nil, # allocates a "table name" into which exceptions are saved (defaults to nil) + email: nil, # sends exception emails to a listed email (string // "you@email.com") + + # On default 5xx error page, social media links included + social: { + facebook: nil, # Facebook page name + twitter: nil, # Twitter handle + youtube: nil, # Youtube channel name / ID + linkedin: nil, # LinkedIn name + fusion: nil # FL Fusion handle + }, + + # This is an entirely NEW structure for the "layouts" area + # You're able to define layouts, notifications etc ↴ + + # All keys interpolated as strings, so you can use symbols, strings or integers where necessary + exceptions: { + + :all => { + layout: "exception", # define layout + notification: true, # (false by default) + deliver: #something here to control the type of response + }, + :4xx => { + layout: nil, # define layout + notification: true, # (false by default) + deliver: #something here to control the type of response + }, + :5xx => { + layout: "exception", # define layout + notification: true, # (false by default) + deliver: #something here to control the type of response + }, + 500 => { + layout: "exception", # define layout + notification: true, # (false by default) + deliver: #something here to control the type of response + }, + + # This is the old structure + # Still works but will be deprecated in future versions + + 501 => "exception", + 502 => "exception", + 503 => "exception", + 504 => "exception", + 505 => "exception", + 507 => "exception", + 510 => "exception" + + } + } -**From [`0.4.7`](https://github.com/richpeck/exception_handler/releases/tag/0.4.6), `ExceptionHandler` manages its [config](lib/exception_handler/config.rb#L45) from the central Rails `config` hash:** + end +end +``` -[![config][config]](lib/exception_handler/config.rb#L45) +For a full retinue of the available options, you'll be best looking at the [`config`](https://github.com/richpeck/exception_handler/blob/master/lib/exception_handler/config.rb) file itself. -If you're using an [`engine`](http://guides.rubyonrails.org/engines.html), you don't need to use an `initializer`: +-- + +If using an [`engine`](http://guides.rubyonrails.org/engines.html), **DON'T need an `initializer`**: # lib/engine.rb module YourModule @@ -152,45 +251,58 @@ If you're using an [`engine`](http://guides.rubyonrails.org/engines.html), you d # => ExceptionHandler # => Works in and out of an initializer config.exception_handler = { - dev: false, - db: true + dev: nil, # => this will not load the gem in development + db: true # => this will use the :errors table to store exceptions } end end -You only need to provide the inputs you want, for example: +The best thing about using a `config` options block is that you are able to only define the options that you require. This means that if you have particular options you *only* wish to run in `staging`, or have single options for `production` etc... - # config/application.rb - config.exception_handler = { dev: true } +--- - # config/environments/production.rb - config.exception_handler = { social: { fusion: "flutils" }} +

+

💻 Dev 💻

+

----- +As explained, `ExceptionHandler` does not work in `development` mode by default. This is because it overrides the `exceptions_app` middleware hook - which is only invoked in `production` or `staging`... + +

+ +

-## Dev Mode +To get it working in `development`, you need to override the [`config.consider_all_requests_local`](http://guides.rubyonrails.org/configuring.html#rails-general-configuration) setting (a standard component of Rails) - setting it to "false" ↴ -**To enable `ExceptionHandler` in dev, enable the [`dev`](lib/exception_handler/config.rb#L38) option:** +

+ +

-![Dev][dev_mode] +This is normally done by changing the setting in your Rails config files. However, to make the process simpler for `ExceptionHandler`- we've added a `dev` option which allows you to override the hook through the context of the gem... + +``` +# config/application.rb +config.exception_handler = { dev: true } +``` This disables [`config.consider_all_requests_local`](http://guides.rubyonrails.org/configuring.html#rails-general-configuration), making Rails behave as it would in production: ![Dev][dev_img] +Obviously, this has other connotations including the likes of making your requests go through your production server etc. For this reason, it's *STRONGLY* recommended you only use the `dev` option to test your layouts etc. + ---- -## Database +

+

💾 Database 💾

+

-**We also have `ActiveRecord` integration.** +If you want to save exceptions to your database, you will need to migrate a new -If you want to save your exceptions to `db`, you need to enable the `db` config option: - - # config/application.rb - config.exception_handler = { - db: true - } +``` +# config/application.rb +config.exception_handler = { db: true } +``` This enables `ActiveRecord::Base` on the [`Exception`](app/models/exception_handler/exception.rb) class, allowing us to save to the database. @@ -200,7 +312,9 @@ To do this, once you've enabled the option, run `rails db:migrate` from your con --- -## Email +

+

✉️ Email ✉️

+

**`ExceptionHandler` also now sends email notifications.** @@ -217,22 +331,43 @@ If you want to receive emails whenever your application raises an error, you can --- -## Views +

+

👓 Views 👓

+

-**From [`0.7.0`](#070), we overhauled the view system:** +The **views** system in `ExceptionHandler` is modular. -![View][view_img] +What *most* people want out of the view is to change the way it ***looks***. This can be done without changing the exception "view" itself... + +

+ +

-[Wiew](app/views/exception_handler/exceptions/show.html.erb) is modular - `@exception` populated with [`locales`](#locales). +To better explain, if [`ExceptionsController`](https://github.com/richpeck/exception_handler/blob/0.8/app/controllers/exception_handler/exceptions_controller.rb) is invoked (by `exceptions_app`), it has **ONE** method ([`show`](https://github.com/richpeck/exception_handler/blob/0.8/app/controllers/exception_handler/exceptions_controller.rb#L42)). This method calls the [`show` view](https://github.com/richpeck/exception_handler/blob/0.8/app/views/exception_handler/exceptions/show.html.erb), which is *entirely* dependent on the locales for content & the layout for the look. + +This means that if you wish to change how the view "looks" - you're *either* going to want to change your *layouts* or the [*locales*](#locales). There is NO reason to change the `show` view itself - it's succinct and entirely modular. Whilst you're definitely at liberty to change it, you'll just be making the issue more complicated than it needs to be. + +- + +If you wish to change the "layout" / "look", there are **two** options... + + * Firstly, you can create your own layout. This is done by changing the + + * Secondly, --- -## Locales +

+

💬 Locales 💬

+

+ +Locales are used to denote interchangeable text (for different languages). -**[`0.7.5`](https://github.com/richpeck/exception_handler/releases/tag/0.7.5) introduced [locales](config/locales/exception_handler.yml) ...** +We've used it for a different purpose - to provide text for our "show" view. The beauty of this is that 1) It's entirely modular & 2) It's extensible (we are able to use as many locales as required)... [[ locales ]] + The `ExceptionHandler` view is populated by [`@exception.description`](app/models/exception_handler/exception.rb#L121), which pulls from the `locales`. If you want custom messages, you need the following. The key is defined by the HTTP [`status_code`](https://github.com/rack/rack/blob/1.5.2/lib/rack/utils.rb#L544) @@ -248,13 +383,13 @@ You get access to `%{message}` and `%{status}`, both inferring from `@exception` --- -## Layout - -**The `layout` has also been improved ↴** +

+

📋 Layouts 📋

+

![Layout][layout_img] -We now assign layouts to the **status code** of the response: +If you want to change the various layouts, you need to use the [`config`](#config) to set them. ![Layout][layouts_img] @@ -263,7 +398,9 @@ By default, `5xx` errors are shown with our [`exception` layout][layout] - this --- -## Custom Exceptions +

+

⛔️ Custom Exceptions ⛔️

+

**Custom Exceptions also supported in [`0.7.5`](https://github.com/richpeck/exception_handler/releases/tag/0.7.5)** @@ -280,7 +417,9 @@ Because `HTTP` can only process `4xx` / `5xx` errors, if `Rails` raises an excep --- -## Generators +

+

💼 Generators 💼

+

**You can generate `ExceptionHandler` into your own application.** @@ -301,34 +440,79 @@ Each switch defines which folders you want (EG `-v views` will only copy `views` --- -### Migrations (deprecated) +

+

✔️ Migrations (deprecated) ✔️

+

+ +**You *DON'T* need to generate a migration any more**. -**From [`0.7.5`](https://github.com/richpeck/exception_handler/releases/tag/0.7.5), the `migration` generator has been removed in favour of our own [migration system](lib/exception_handler/engine.rb#L58)** +From [`0.7.5`](https://github.com/richpeck/exception_handler/releases/tag/0.7.5), the `migration` generator has been removed in favour of our own [migration system](lib/exception_handler/engine.rb#L58). -You don't need to generate a migration any more. +The reason we did this was so not to pollute your migrations folder with a worthless file. Our migration doesn't need to be changed - we only have to get it into the database and the gem takes care of the rest... -If you set the `db` option in config, run `rails db:migrate` and the migration will be run. +> If you set the `db` option in config, run `rails db:migrate` and the migration will be run. To rollback, use the following: rails db:migrate:down VERSION=000000 -> The drawback to this is that if you remove `ExceptionHandler` before you rollback the migration, it won't exist anymore. You can **only** fire the `rollback` when you have `ExceptionHandler` installed. +The drawback to this is that if you remove `ExceptionHandler` before you rollback the migration, it won't exist anymore. You can **only** fire the `rollback` when you have `ExceptionHandler` installed. ---- + +
+

+

☎️ Support ☎️

+

+
-## Support +

🚨 Obviously, if you've taken the time to use the gem, it makes sense to support it 🚨!

-[Issues](https://github.com/richpeck/exception_handler/issues) +The fastest way to get a **direct response** is via [email](mailto:rpeck@frontlineutilities.co.uk). ---- +You're also welcome to access our [**Issues**](https://github.com/richpeck/exception_handler/issues) page to contact us directly. You could also use [**StackOverflow**](https://stackoverflow.com/questions/tagged/ruby-on-rails+exceptionhandler)... + + - ⚠️ [**Issues**](https://github.com/richpeck/exception_handler/issues) ⚠️ + - 🚩 [**StackOverflow**](https://stackoverflow.com/questions/tagged/ruby-on-rails+exceptionhandler) 🚩 + - ✉️ [**Email**](mailto:rpeck@frontlineutilities.co.uk) ✉️ + - ✏️ [**Medium**](https://medium.com/ruby-on-rails-web-application-development/custom-400-500-error-pages-in-ruby-on-rails-exception-handler-3a04975e4677) ✏️ + - 🎥 [**YouTube**](https://www.youtube.com/channel/UC247lm76ECX1aSvVuhXxe6g) 🎥 ↴ + +

+ +

+ + +
+

+

⭐ Changelog ⭐

+

+
-## Changelog +The most important thing to appreciate is... -### [0.7.5](https://github.com/richpeck/exception_handler/releases/tag/0.7.5) +

➡️ ExceptionHandler is designed to provide custom error pages for Ruby on Rails. ⬅️

+ +

If you're looking at adding extra functionality (such as a debugger), you'll probably be better looking at the likes of better_errors or gaffe. Whilst we'll certainly look at adding - or integrating - other features (if they're requested), our core intention has always been to provide an exception handling stack that was both simple and customizable.

+ +-- + +What we've built so far... + +### 👻 [1.0.0.0](https://github.com/richpeck/exception_handler/releases/tag/v1.0.0.0) + - [ ] TBA + +### 🏹 [0.8.0.0](https://github.com/richpeck/exception_handler/releases/tag/v0.8.0.0) + - [x] [README](https://github.com/richpeck/exception_handler/issues/52) (focus on utility) + - [x] Introduction of `4xx`,`5xx`,`:all` for layouts config + - [x] Changed `layouts` to `exceptions` in config + - [x] Email improvement + - [x] Streamlined migration + - [x] Updated model + +### 👽 [0.7.7.0](https://github.com/richpeck/exception_handler/releases/tag/v0.7.7.0) - [x] [HTTP status layouts](#layouts) -### [0.7.0](https://github.com/richpeck/exception_handler/releases/tag/0.7.0) +### ⚡ 0.7.0.0 - [x] Wildcard mime types - [x] [Custom exceptions](#custom_exceptions) - [x] Test suite integration @@ -338,7 +522,7 @@ To rollback, use the following: - [x] New layout - [x] Readme / wiki overhaul -### [0.6.5](https://github.com/richpeck/exception_handler/releases/tag/0.6.5) +### Ⓜ️ 0.6.5.0 - [x] Streamlined interface - [x] ActiveRecord / Middleware overhaul - [x] Supports Sprockets 4+ ([`manifest.js`](http://eileencodes.com/posts/the-sprockets-4-manifest/)) @@ -346,7 +530,7 @@ To rollback, use the following: - [x] Asset overhaul & improvement - [x] Removed dependencies -### [0.5.0](https://github.com/richpeck/exception_handler/releases/tag/0.5.0) +### ✔️ 0.5.0.0 - [x] Locales - [x] Email notifications - [x] Full test suite @@ -357,20 +541,23 @@ To rollback, use the following: - [x] Rails asset management improvement - [x] Reduced gem file size -### [0.4.7](https://github.com/richpeck/exception_handler/releases/tag/0.4.6) +### ⭕ 0.4.7.0 - [x] New config system - [x] Fixed controller layout issues - [x] Streamlined middleware - [x] New layout & interface ----- + +

+ +

[![404 + 500 Errors][banner]][rubygems]

- ExceptionHandler is now the leading custom error pages gem for Rails. + ExceptionHandler is now the • LEADING • custom error pages gem for Rails 4 & 5...
- No other gem is as simple or effective at providing beautiful exception pages in production. + No other gem is as simple or effective at providing branded exception pages in production...

@@ -383,12 +570,16 @@ To rollback, use the following:

- Download Here + ➡️ Download & Info ⬅️ +

+ + +

+

----------- +:copyright: -:copyright: @@ -436,5 +627,11 @@ To rollback, use the following: [pull]: http://github.com/richpeck/exception_handler/pulls [issues]: http://github.com/richpeck/exception_handler/issues +[10x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#1xx_Informational_responses +[20x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success +[30x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection +[40x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors +[50x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_errors + diff --git a/app/assets/stylesheets/exception_handler.css.erb b/app/assets/stylesheets/exception_handler.css.erb index afcb6422..77051c4e 100644 --- a/app/assets/stylesheets/exception_handler.css.erb +++ b/app/assets/stylesheets/exception_handler.css.erb @@ -15,4 +15,9 @@ */ /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ +/* + *= link_tree ../images +*/ +/* ---------------------------------------------------- */ +/* ---------------------------------------------------- */ /* ---------------------------------------------------- */ diff --git a/app/assets/stylesheets/styles/_base.css.erb b/app/assets/stylesheets/styles/_base.css.erb index 4d603b5a..c7e85bb9 100644 --- a/app/assets/stylesheets/styles/_base.css.erb +++ b/app/assets/stylesheets/styles/_base.css.erb @@ -4,19 +4,12 @@ /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ -/* - *= link_tree ../../images -*/ - -/* ---------------------------------------------------- */ -/* ---------------------------------------------------- */ - * { margin: 0; } html, body { height: 100%; } html { height: 100%; color: #fff; - background: #010008 url(<%= asset_url("exception_handler/bg.jpg") %>) top left no-repeat; + background: #121212; background-size: 100% 100%; box-sizing: border-box; } diff --git a/app/assets/stylesheets/styles/_exception.css.erb b/app/assets/stylesheets/styles/_exception.css.erb index 2027b1eb..4d9ef5fe 100644 --- a/app/assets/stylesheets/styles/_exception.css.erb +++ b/app/assets/stylesheets/styles/_exception.css.erb @@ -53,7 +53,8 @@ border-color: rgba(255,255,255,0.09); border-style: solid } -.exception:hover { cursor: pointer; } +.exception:hover { cursor: pointer; } +.exception:hover:after { text-decoration: underline; } .exception span:before { display: block; diff --git a/app/controllers/exception_handler/exceptions_controller.rb b/app/controllers/exception_handler/exceptions_controller.rb index 7c078b34..4f2f2389 100644 --- a/app/controllers/exception_handler/exceptions_controller.rb +++ b/app/controllers/exception_handler/exceptions_controller.rb @@ -36,9 +36,11 @@ class ExceptionsController < ApplicationController layout :layout #################### - # Action # + # Actions # #################### + # => General Show Functionality + # => Introduced new "action" config option in 0.8.0.0 def show respond_with @exception, status: @exception.status end @@ -48,8 +50,13 @@ def show private - def layout - ExceptionHandler.config.layouts[@exception.status] + # => Pulls from Exception class + # => Spanner in the works is nil + # => .present? validates against empty strings (IE a string is present) + # => .nil? validates to see if the returned data is "nil" + # => nil required to facilitate inheritance of the layout w/ ApplicationController + def layout option = ExceptionHandler.config.options(@exception.status, :layout) + (option.present? || option.nil?) ? option : 'exception' end ################################## diff --git a/app/models/exception_handler/exception.rb b/app/models/exception_handler/exception.rb index a144c859..f9e3803e 100644 --- a/app/models/exception_handler/exception.rb +++ b/app/models/exception_handler/exception.rb @@ -10,20 +10,13 @@ module ExceptionHandler # => Attributes # => Determine schema etc ATTRS = %i(class_name status message trace target referrer params user_agent) - - # => Exceptions to be rescued by ExceptionHandler - EXCEPTIONS_TO_BE_RESCUED = [ActionController::RoutingError, AbstractController::ActionNotFound].tap do |list| - list << ActiveRecord::RecordNotFound if defined?(ActiveRecord) - list << Mongoid::Errors::DocumentNotFound if defined?(Mongoid) - end ############################################################ ############################################################ # => Class (inheritance dependent on whether db option is available) - self::Exception = Class.new( - (ExceptionHandler.config.try(:db) && defined?(ActiveRecord)) ? ActiveRecord::Base : Object - ) do + self::Exception = + Class.new( (ExceptionHandler.config.try(:db) && defined?(ActiveRecord)) ? ActiveRecord::Base : Object ) do # => Include individual elements # => Only required if no db present (no ActiveRecord) @@ -97,15 +90,14 @@ def self.table_name # => Email # => after_initialize invoked after .new method called # => Should have been after_create but user may not save - after_initialize Proc.new { |e| ExceptionHandler::ExceptionMailer.new_exception(e).deliver } if ExceptionHandler.config.try(:email).try(:is_a?, String) + after_initialize -> (e) { ExceptionHandler::ExceptionMailer.new_exception(e).deliver }, if: :email? # => see bottom of file # => Attributes attr_accessor :request, :klass, :exception, :description attr_accessor *ATTRS unless ExceptionHandler.config.try(:db) # => Validations - validates :klass, exclusion: { in: EXCEPTIONS_TO_BE_RESCUED, message: "%{value}" }, if: -> { referer.blank? } # => might need full Proc syntax - validates :user_agent, format: { without: Regexp.new( BOTS.join("|"), Regexp::IGNORECASE ) } + validates :user_agent, format: { without: Regexp.new( BOTS.join("|"), Regexp::IGNORECASE ) } ################################## ################################## @@ -114,21 +106,22 @@ def self.table_name # Virtual #################################### + # => Exception (virtual) + # => Basis on which all the class is built + def exception + request.env['action_dispatch.exception'] + end + # => Klass # => Used for validation (needs to be cleaned up in 0.7.0) def klass exception.class end - # => Exception (virtual) - def exception - request.env['action_dispatch.exception'] - end - # => Description def description I18n.with_options scope: [:exception_handler], message: message, status: status do |i18n| - i18n.t response, default: Rack::Utils::HTTP_STATUS_CODES[status] || status + i18n.t response, default: Rack::Utils::HTTP_STATUS_CODES[status] end end @@ -143,7 +136,7 @@ def class_name # => Message def message - exception.message + exception ? exception.message : Rack::Utils::HTTP_STATUS_CODES[status] end # => Trace @@ -181,7 +174,7 @@ def user_agent # => Status code (404, 500 etc) def status - ActionDispatch::ExceptionWrapper.new(request.env, exception).status_code + exception ? ActionDispatch::ExceptionWrapper.new(request.env, exception).try(:status_code) : request.env["PATH_INFO"][1..-1].to_i end # => Server Response ("Not Found" etc) @@ -192,6 +185,14 @@ def response ################################## ################################## + private + + # => Email + # => should be on the same line as after_initialize but too long + def email? + ExceptionHandler.config.try(:email).try(:is_a?, String) && ExceptionHandler.config.options(status, :notification) != false + end + end end diff --git a/app/views/exception_handler/exceptions/show.html.erb b/app/views/exception_handler/exceptions/show.html.erb index 0d56a351..5e036cd1 100644 --- a/app/views/exception_handler/exceptions/show.html.erb +++ b/app/views/exception_handler/exceptions/show.html.erb @@ -1,3 +1,3 @@ -<%= content_tag :div, class: "exception", data: { status: @exception.status, response: @exception.response.to_s.humanize, rails: Rails.version }, onclick: ("location.href=\"#{root_url}\";" if @exception.status == "500" && Rails.application.routes.recognize_path("/")), title: ("Return Home" if @exception.status == "500" && Rails.application.routes.recognize_path("/")) do %> +<%= content_tag :div, class: "exception", data: { status: @exception.status, response: @exception.response.to_s.humanize, rails: Rails.version }, onclick: ("location.href=\"#{root_url}\";" if @exception.status.to_s.first == "5" && Rails.application.routes.recognize_path("/")) do %> <%= content_tag :span, @exception.description.html_safe %> <% end %> diff --git a/app/views/layouts/exception.html.erb b/app/views/layouts/exception.html.erb index cf772ebc..ff249554 100644 --- a/app/views/layouts/exception.html.erb +++ b/app/views/layouts/exception.html.erb @@ -9,6 +9,10 @@ <%= stylesheet_link_tag :exception_handler %> <%= favicon_link_tag "exception_handler/favicon.ico" %> + <% if x = ExceptionHandler.config.options(@exception.status) %> + + <% end %> + <%= csrf_meta_tags %> @@ -24,4 +28,5 @@ <% end %> <% end %> <% end %> + diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 00000000..cadd72dc --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,5 @@ + + + + <%= yield %> + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 00000000..37f0bddb --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/config/locales/exception_handler.en.yml b/config/locales/exception_handler.en.yml index 6fca6dec..aa8d6cd1 100644 --- a/config/locales/exception_handler.en.yml +++ b/config/locales/exception_handler.en.yml @@ -22,7 +22,7 @@ en: exception_handler: - internal_server_error: "%{status} Error %{message}

Return home

" + internal_server_error: "%{status} Error %{message}" ####################################################################################### ####################################################################################### diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 00000000..498cc316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,42 @@ +######################################## +######################################## +## _____ _ ## +## | ___ \ | | ## +## | |_/ /___ _ _| |_ ___ ___ ## +## | // _ \| | | | __/ _ \/ __| ## +## | |\ \ (_) | |_| | || __/\__ \ ## +## \_| \_\___/ \__,_|\__\___||___/ ## +## ## +######################################## +######################################## + +## Good resource +## https://gist.github.com/maxivak/5d428ade54828836e6b6#merge-engine-and-app-routes + +######################################## +######################################## + +## Routes ## +Rails.application.routes.draw do + + ######################################## + ######################################## + + # => ExceptionHandler + # => Used to provide error page examples in "dev" mode + if Object.const_defined?('ExceptionHandler') && ExceptionHandler.config.try(:dev) + + # => Items + Rack::Utils::SYMBOL_TO_STATUS_CODE.select{ |key, value| value.to_s.match('\b(?:4[0-9]{2}|5[0-9]{2}|599)\b') }.each do |code, status| + get status.to_s, to: 'exception_handler/exceptions#show', as: code, code: code + end + + end + + ######################################## + ######################################## + +end + +######################################## +######################################## diff --git a/exception_handler.gemspec b/exception_handler.gemspec index 89c833ef..da435034 100644 --- a/exception_handler.gemspec +++ b/exception_handler.gemspec @@ -11,16 +11,17 @@ require_relative 'lib/exception_handler/version' Gem::Specification.new do |s| ## General ## - s.name = "exception_handler" - s.authors = ["R.Peck"] - s.email = ["rpeck@fl.co.uk"] - s.version = ExceptionHandler::VERSION::STRING - s.platform = Gem::Platform::RUBY + s.name = "exception_handler" + s.authors = ["R.Peck"] + s.email = ["rpeck@fl.co.uk"] + s.version = ExceptionHandler::VERSION::STRING + s.platform = Gem::Platform::RUBY ## Details ## - s.summary = %q{Rails gem to show custom error pages in production. Also logs errors in db & sends notification emails} - s.description = %q{Rails gem to create custom error pages. Captures exceptions using "exception_app" callback, routing to "Exception" controller, rendering the view as required.} - s.homepage = "https://github.com/richpeck/exception_handler" + s.summary = %q{Rails gem to show custom error pages in production. Also logs errors in db & sends notification emails} + s.description = %q{Rails gem to create custom error pages. Captures exceptions using "exception_app" callback, routing to "Exception" controller, rendering the view as required.} + s.post_install_message = %q{ExceptionHandler 0.8.0.0 → New "config" (config.exception_handler = {exceptions: {layout: 'x', notification: true, action: {redirect_to root_path} }} ). https://www.github.com/richpeck/exception_handler#config for more info. } + s.homepage = "https://github.com/richpeck/exception_handler" ## License ## s.license = "MIT" diff --git a/lib/exception_handler.rb b/lib/exception_handler.rb index f2377dc3..c3c9ab38 100644 --- a/lib/exception_handler.rb +++ b/lib/exception_handler.rb @@ -37,6 +37,7 @@ class Error < StandardError; end ############################## ############################## + end ######################################################### diff --git a/lib/exception_handler/config.rb b/lib/exception_handler/config.rb index 5f2c7c11..31003f4a 100644 --- a/lib/exception_handler/config.rb +++ b/lib/exception_handler/config.rb @@ -7,7 +7,7 @@ ## | \__/\ (_) | | | | | | | (_| | ## ## \____/\___/|_| |_|_| |_|\__, | ## ## __/ | ## -## |___/ ## +## |___/ ## ########################################### ########################################### @@ -26,9 +26,10 @@ class Config # => ExceptionHandler.config.db # => ExceptionHandler.config.email # => ExceptionHandler.config.social - # => ExceptionHandler.config.layouts + # => ExceptionHandler.config.layouts -> will need to be deprecated + # => ExceptionHandler.config.exceptions # => ExceptionHandler.config.custom_exceptions - attr_accessor :dev, :db, :email, :social, :layouts, :custom_exceptions + attr_accessor :dev, :db, :email, :social, :layouts, :exceptions, :custom_exceptions ########################################### ########################################### @@ -39,51 +40,96 @@ class Config # => Has to be "errors" because "exceptions" is a reserved word TABLE = :errors + ########################################### + ########################################### + # => Social URLs # => Extracted from "social" block - SOCIAL = { - facebook: "https://facebook.com", - twitter: "https://twitter.com", - youtube: "https://youtube.com/user", - linkedin: "https://linkedin.com/company", - fusion: "https://frontlinefusion.com" - } + SOCIAL = + ActiveSupport::HashWithIndifferentAccess.new({ + facebook: "https://www.facebook.com", + twitter: "https://www.twitter.com", + youtube: "https://www.youtube.com/user", + linkedin: "https://www.linkedin.com/company", + fusion: "https://www.frontlinefusion.com" + }) ########################################### ########################################### # => Defaults # => http://stackoverflow.com/a/8917301/1143732 - DEFAULTS = { - dev: nil, # => defaults to "false" for dev mode - db: nil, # => defaults to :errors if true, else use "table_name" / :table_name - email: nil, # => requires string email and ActionMailer - social: { - facebook: nil, - twitter: nil, - youtube: nil, - linkedin: nil, - fusion: nil, - }, - layouts: { - # => nil inherits from ApplicationController - # => 4xx errors should be nil - # => 5xx errors should be "exception" but can be nil if explicitly defined - 500 => "exception", - 501 => "exception", - 502 => "exception", - 503 => "exception", - 504 => "exception", - 505 => "exception", - 507 => "exception", - 510 => "exception" - } - } - - ########################################### - ########################################### - - # => Init + DEFAULTS = + ActiveSupport::HashWithIndifferentAccess.new({ + + # => General options + dev: nil, # => defaults to "false" for dev mode + db: nil, # => defaults to :errors if true, else use "table_name" / :table_name + email: nil, # => requires string email and ActionMailer + + # => Used in "exception" layout + social: { + facebook: nil, + twitter: nil, + youtube: nil, + linkedin: nil, + fusion: nil, + }, + + # => Defaults for exceptions. Override with specific status codes + # => Please note these are all STRINGS + exceptions: { + + # => 4xx/5xx base standard + # => :all provide block customization (overrides 4xx/5xx) + # => specific provides individual (overrides all) + + # => 4xx Errors (resource not found) + # => https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors + '4xx' => { + layout: nil + # notification: true #(this is for emails - it's true by default - only if you have email inputted) + # action: ____, (this is general) + # background: (can define custom background for exceptions layout if required) + }, + + # => 5xx Errors (server error) + # => https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_errors + '5xx' => { + layout: 'exception' + # notification: true (this is for emails - it's true by default - only if you have email inputted) + # action: _____, (this is general) + # background: (can define custom background for exceptions layout if required) + } + }, + + # Deprecated + #layouts: { + # => nil inherits from ApplicationController + # => 4xx errors should be nil + # => 5xx errors should be "exception" but can be nil if explicitly defined + #500 => 'exception', + #501 => 'exception', + #502 => 'exception', + #503 => 'exception', + #504 => 'exception', + #505 => 'exception', + #507 => 'exception', + #510 => 'exception' + #}, + + # => If you want to map your own classes to HTTP errors + # => use this... + custom_exceptions: { + #'ActionController::RoutingError' => :not_found # => example + } + + }) + + ########################################### + ########################################### + + # => Constructor # => Merges DEFAULTS to values, creates instances vars (for attr_accessor) def initialize values @@ -107,6 +153,29 @@ def db @db == true ? TABLE : @db.try(:parameterize, separator: "_") end + ########################################### + ########################################### + + # => Options + # => Requires argument + def options status, pluck=nil + + # => Structure from old + new setup + # => 1. layouts => [500, '500'] + # => 2. exceptions => [500, '500' 'all', '4xx'/'5xx'] + { layouts: [status, status.to_s], # old + new + exceptions: [status, status.to_s, 'all', status.to_s.first + 'xx'] }.each do |key,array| + + # => Array + # => https://stackoverflow.com/a/26877095/1143732 + array.each do |specific| + item = self.send(key).try(:[], specific) + return (item.is_a?(Hash) ? ActiveSupport::HashWithIndifferentAccess.new(item)[pluck.try(:to_sym)] : item) if item.present? || (self.send(key).try(:has_key?, specific) && item.nil?) #if result exists and it has a value (including nil) + end + + end + end + ########################################### ########################################### ########################################### diff --git a/lib/exception_handler/engine.rb b/lib/exception_handler/engine.rb index d4b5e061..ce18b09c 100644 --- a/lib/exception_handler/engine.rb +++ b/lib/exception_handler/engine.rb @@ -7,7 +7,7 @@ ## | |__| | | | (_| | | | | | __/ ## ## \____/_| |_|\__, |_|_| |_|\___| ## ## __/ | ## -## |___/ ## +## |___/ ## ########################################### ########################################### @@ -39,7 +39,8 @@ class Engine < Rails::Engine # => Config # => Builds lib/exception_handler/config.rb - # config.before_initialize do |app| => Needs to be fixed for ActiveRecord::Base + # => config.before_initialize do |app| => Needs to be fixed for ActiveRecord::Base + # => to support later version of config, "with_indifferent_access" used in config.rb initializer :exception_handler_config, before: "better_errors.configure_rails_initialization" do |app| ExceptionHandler.config ||= ExceptionHandler::Config.new config.try(:exception_handler) end @@ -51,7 +52,14 @@ class Engine < Rails::Engine # => This should be config.before_initialize but because ActiveRecord is not initialized, cannot check for table initializer :exception_handler, before: "better_errors.configure_rails_initialization" do |app| app.config.exceptions_app = ->(env) { ExceptionHandler::ExceptionsController.action(:show).call(env) } - app.config.consider_all_requests_local = !ExceptionHandler.config.try(:dev) if Rails.env.development? + app.config.consider_all_requests_local = !ExceptionHandler.config.try(:dev) if Rails.env.development? || Rails.env.test? + end + + # => Custom Exceptions + # => This just mimicks standard Rails behaviour + # => Look for "config.action_dispatch.rescue_responses" for more info) + initializer :exception_handler_custom_exceptions do |app| + app.config.action_dispatch.rescue_responses.merge! ExceptionHandler.config.custom_exceptions if ExceptionHandler.config.custom_exceptions end # => Migrations diff --git a/lib/exception_handler/version.rb b/lib/exception_handler/version.rb index e334c1ab..a8036ae0 100644 --- a/lib/exception_handler/version.rb +++ b/lib/exception_handler/version.rb @@ -13,8 +13,8 @@ module ExceptionHandler module VERSION MAJOR = 0 - MINOR = 7 - TINY = 7 + MINOR = 8 + TINY = 0 PRE = 0 # "alpha" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") diff --git a/readme/HTTP.png b/readme/HTTP.png new file mode 100644 index 00000000..c91e94f2 Binary files /dev/null and b/readme/HTTP.png differ diff --git a/readme/local_requests.jpg b/readme/local_requests.jpg new file mode 100644 index 00000000..fbb3cc42 Binary files /dev/null and b/readme/local_requests.jpg differ diff --git a/readme/status_codes.png b/readme/status_codes.png new file mode 100644 index 00000000..0e40e1bd Binary files /dev/null and b/readme/status_codes.png differ diff --git a/readme/titles/initial.png b/readme/titles/initial.png new file mode 100644 index 00000000..444ff48f Binary files /dev/null and b/readme/titles/initial.png differ diff --git a/readme/youtube.png b/readme/youtube.png new file mode 100644 index 00000000..0f6792a8 Binary files /dev/null and b/readme/youtube.png differ diff --git a/spec/controllers/controller_spec.rb b/spec/controllers/controller_spec.rb new file mode 100644 index 00000000..c6036f5b --- /dev/null +++ b/spec/controllers/controller_spec.rb @@ -0,0 +1,107 @@ +##################################################### +##################################################### +## _____ _ _ _ ## +## / __ \ | | | | | ## +## | / \/ ___ _ __ | |_ _ __ ___ | | | ___ _ __ ## +## | | / _ \| '_ \| __| '__/ _ \| | |/ _ \ '__| ## +## | \__/\ (_) | | | | |_| | | (_) | | | __/ | ## +## \____/\___/|_| |_|\__|_| \___/|_|_|\___|_| ## +## ## +##################################################### +##################################################### + +require 'spec_helper' + +############################################### +############################################### + +# => ExceptionHandler (Controller) +# => Test erroneous requests under different circumstances +# => Expect the return of 404, 500 (etc) Error Pages +# => Test layout, show action, @exception object and different config options +RSpec.describe ExceptionHandler::ExceptionsController do + + # => General + # => Used to describe the actual Controller class + describe "class" do + subject { controller } + it { should respond_to :show } + end + + ################################# + ################################# + + # => Layout + # => Expected results & overall views + describe "layout" do + #subject { response.layout } + #it { should be_a String } + end + + ################################# + ################################# + + # => Response + # => Should deliver 404 / 500 error responses + # => Should deliver appropriate headers, layout etc + describe "response" do + + # => Before + before(:each) { } + + # => 404 + context "404" do + subject { response } + it { should have_http_status :ok } + + end + + # => 500 + context "500" do + end + + end + + ################################# + ################################# + + # => Dev Routes + # => Should deliver 404 / 500 error responses + # => Should deliver appropriate headers, layout etc + describe "dev routes" do + + # => Item + before(:context) { ExceptionHandler.config.dev = true } + before(:context) { Rails.application.reload_routes! } + + # => Items + let(:dev) { ExceptionHandler.config.dev } + + # => Config + + # => Pages + # => These are shown when + context "pages" do + + # => Dev Mode + # => Only works with dev enabled + it "has Dev mode enabled" do + expect(dev).to eq(true) + end + + # => The error pages need to return the correct status code + #Rack::Utils::SYMBOL_TO_STATUS_CODE.select{ |key, value| value.to_s.match('\b(?:4[0-9]{2}|5[0-9]{2}|599)\b') }.each do |status,code| + # it "shows #{code.to_s} page" do + # get :show, params: { code: status.to_sym } + # expect(response).to have_http_status status.to_sym + # expect(response.body).to match /404/ + # end + #end + + end + end + +end + +############################################### +############################################### diff --git a/spec/dummy/.rspec b/spec/dummy/.rspec new file mode 100644 index 00000000..c99d2e73 --- /dev/null +++ b/spec/dummy/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/spec/dummy/.ruby-version b/spec/dummy/.ruby-version new file mode 100644 index 00000000..4fd0fe3c --- /dev/null +++ b/spec/dummy/.ruby-version @@ -0,0 +1 @@ +2.5.1 \ No newline at end of file diff --git a/spec/dummy/Rakefile b/spec/dummy/Rakefile new file mode 100644 index 00000000..e85f9139 --- /dev/null +++ b/spec/dummy/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative 'config/application' + +Rails.application.load_tasks diff --git a/spec/dummy/app/assets/config/manifest.js b/spec/dummy/app/assets/config/manifest.js new file mode 100644 index 00000000..b16e53d6 --- /dev/null +++ b/spec/dummy/app/assets/config/manifest.js @@ -0,0 +1,3 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css diff --git a/spec/dummy/app/assets/images/.keep b/spec/dummy/app/assets/images/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/dummy/app/assets/javascripts/application.js b/spec/dummy/app/assets/javascripts/application.js new file mode 100644 index 00000000..67ce4675 --- /dev/null +++ b/spec/dummy/app/assets/javascripts/application.js @@ -0,0 +1,15 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// +//= require rails-ujs +//= require activestorage +//= require_tree . diff --git a/spec/dummy/app/assets/javascripts/cable.js b/spec/dummy/app/assets/javascripts/cable.js new file mode 100644 index 00000000..739aa5f0 --- /dev/null +++ b/spec/dummy/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/spec/dummy/app/assets/javascripts/channels/.keep b/spec/dummy/app/assets/javascripts/channels/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/dummy/app/assets/stylesheets/application.css b/spec/dummy/app/assets/stylesheets/application.css new file mode 100644 index 00000000..0ebd7fe8 --- /dev/null +++ b/spec/dummy/app/assets/stylesheets/application.css @@ -0,0 +1,15 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + *= require_tree . + *= require_self + */ diff --git a/spec/dummy/app/channels/application_cable/channel.rb b/spec/dummy/app/channels/application_cable/channel.rb new file mode 100644 index 00000000..d6726972 --- /dev/null +++ b/spec/dummy/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/spec/dummy/app/channels/application_cable/connection.rb b/spec/dummy/app/channels/application_cable/connection.rb new file mode 100644 index 00000000..0ff5442f --- /dev/null +++ b/spec/dummy/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/spec/dummy/app/controllers/application_controller.rb b/spec/dummy/app/controllers/application_controller.rb new file mode 100644 index 00000000..09705d12 --- /dev/null +++ b/spec/dummy/app/controllers/application_controller.rb @@ -0,0 +1,2 @@ +class ApplicationController < ActionController::Base +end diff --git a/spec/dummy/app/controllers/concerns/.keep b/spec/dummy/app/controllers/concerns/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/dummy/app/helpers/application_helper.rb b/spec/dummy/app/helpers/application_helper.rb new file mode 100644 index 00000000..de6be794 --- /dev/null +++ b/spec/dummy/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/spec/dummy/app/jobs/application_job.rb b/spec/dummy/app/jobs/application_job.rb new file mode 100644 index 00000000..a009ace5 --- /dev/null +++ b/spec/dummy/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/spec/dummy/app/mailers/application_mailer.rb b/spec/dummy/app/mailers/application_mailer.rb new file mode 100644 index 00000000..286b2239 --- /dev/null +++ b/spec/dummy/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: 'from@example.com' + layout 'mailer' +end diff --git a/spec/dummy/app/models/application_record.rb b/spec/dummy/app/models/application_record.rb new file mode 100644 index 00000000..10a4cba8 --- /dev/null +++ b/spec/dummy/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/spec/dummy/app/models/concerns/.keep b/spec/dummy/app/models/concerns/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/dummy/app/views/layouts/application.html.erb b/spec/dummy/app/views/layouts/application.html.erb new file mode 100644 index 00000000..6093a4c8 --- /dev/null +++ b/spec/dummy/app/views/layouts/application.html.erb @@ -0,0 +1,15 @@ + + + + Dummy + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= stylesheet_link_tag 'application', media: 'all' %> + <%= javascript_include_tag 'application' %> + + + + <%= yield %> + + diff --git a/spec/dummy/app/views/layouts/mailer.html.erb b/spec/dummy/app/views/layouts/mailer.html.erb new file mode 100644 index 00000000..cbd34d2e --- /dev/null +++ b/spec/dummy/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/spec/dummy/app/views/layouts/mailer.text.erb b/spec/dummy/app/views/layouts/mailer.text.erb new file mode 100644 index 00000000..37f0bddb --- /dev/null +++ b/spec/dummy/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/spec/dummy/bin/bundle b/spec/dummy/bin/bundle new file mode 100644 index 00000000..8d5f7a57 --- /dev/null +++ b/spec/dummy/bin/bundle @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby.exe +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) +load Gem.bin_path('bundler', 'bundle') diff --git a/spec/dummy/bin/rails b/spec/dummy/bin/rails new file mode 100644 index 00000000..bec72ac2 --- /dev/null +++ b/spec/dummy/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby.exe +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/spec/dummy/bin/rake b/spec/dummy/bin/rake new file mode 100644 index 00000000..f6ed5a2a --- /dev/null +++ b/spec/dummy/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby.exe +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/spec/dummy/bin/setup b/spec/dummy/bin/setup new file mode 100644 index 00000000..237a371b --- /dev/null +++ b/spec/dummy/bin/setup @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby.exe +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') + + # puts "\n== Copying sample files ==" + # unless File.exist?('config/database.yml') + # cp 'config/database.yml.sample', 'config/database.yml' + # end + + puts "\n== Preparing database ==" + system! 'bin/rails db:setup' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/spec/dummy/bin/update b/spec/dummy/bin/update new file mode 100644 index 00000000..1db4ab55 --- /dev/null +++ b/spec/dummy/bin/update @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby.exe +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a way to update your development environment automatically. + # Add necessary update steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') + + puts "\n== Updating database ==" + system! 'bin/rails db:migrate' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/spec/dummy/bin/yarn b/spec/dummy/bin/yarn new file mode 100644 index 00000000..33898225 --- /dev/null +++ b/spec/dummy/bin/yarn @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby.exe +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + begin + exec "yarnpkg", *ARGV + rescue Errno::ENOENT + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 + end +end diff --git a/spec/dummy/config.ru b/spec/dummy/config.ru new file mode 100644 index 00000000..f7ba0b52 --- /dev/null +++ b/spec/dummy/config.ru @@ -0,0 +1,5 @@ +# This file is used by Rack-based servers to start the application. + +require_relative 'config/environment' + +run Rails.application diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb new file mode 100644 index 00000000..9264f907 --- /dev/null +++ b/spec/dummy/config/application.rb @@ -0,0 +1,18 @@ +require_relative 'boot' + +require 'rails/all' + +Bundler.require(*Rails.groups) +require 'exception_handler' + +module Dummy + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 5.2 + + # Settings in config/environments/* take precedence over those specified here. + # Application configuration can go into files in config/initializers + # -- all .rb files in that directory are automatically loaded after loading + # the framework and any gems in your application. + end +end diff --git a/spec/dummy/config/boot.rb b/spec/dummy/config/boot.rb new file mode 100644 index 00000000..c9aef85d --- /dev/null +++ b/spec/dummy/config/boot.rb @@ -0,0 +1,5 @@ +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) + +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) diff --git a/spec/dummy/config/cable.yml b/spec/dummy/config/cable.yml new file mode 100644 index 00000000..1cd0f836 --- /dev/null +++ b/spec/dummy/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: dummy_production diff --git a/spec/dummy/config/database.yml b/spec/dummy/config/database.yml new file mode 100644 index 00000000..0d02f249 --- /dev/null +++ b/spec/dummy/config/database.yml @@ -0,0 +1,25 @@ +# SQLite version 3.x +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem 'sqlite3' +# +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/spec/dummy/config/environment.rb b/spec/dummy/config/environment.rb new file mode 100644 index 00000000..426333bb --- /dev/null +++ b/spec/dummy/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative 'application' + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/spec/dummy/config/environments/development.rb b/spec/dummy/config/environments/development.rb new file mode 100644 index 00000000..366e75ad --- /dev/null +++ b/spec/dummy/config/environments/development.rb @@ -0,0 +1,61 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join('tmp', 'caching-dev.txt').exist? + config.action_controller.perform_caching = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Store uploaded files on the local file system (see config/storage.yml for options) + config.active_storage.service = :local + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true + + # Use an evented file watcher to asynchronously detect changes in source code, + # routes, locales, etc. This feature depends on the listen gem. + # config.file_watcher = ActiveSupport::EventedFileUpdateChecker +end diff --git a/spec/dummy/config/environments/production.rb b/spec/dummy/config/environments/production.rb new file mode 100644 index 00000000..9ea5ad27 --- /dev/null +++ b/spec/dummy/config/environments/production.rb @@ -0,0 +1,94 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? + + # Compress JavaScripts and CSS. + config.assets.js_compressor = :uglifier + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.action_controller.asset_host = 'http://assets.example.com' + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options) + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain + # config.action_cable.mount_path = nil + # config.action_cable.url = 'wss://example.com/cable' + # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. + config.log_level = :debug + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment) + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "dummy_#{Rails.env}" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners. + config.active_support.deprecation = :notify + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require 'syslog/logger' + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/spec/dummy/config/environments/test.rb b/spec/dummy/config/environments/test.rb new file mode 100644 index 00000000..0a38fd3c --- /dev/null +++ b/spec/dummy/config/environments/test.rb @@ -0,0 +1,46 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true +end diff --git a/spec/dummy/config/initializers/application_controller_renderer.rb b/spec/dummy/config/initializers/application_controller_renderer.rb new file mode 100644 index 00000000..89d2efab --- /dev/null +++ b/spec/dummy/config/initializers/application_controller_renderer.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/spec/dummy/config/initializers/assets.rb b/spec/dummy/config/initializers/assets.rb new file mode 100644 index 00000000..4b828e80 --- /dev/null +++ b/spec/dummy/config/initializers/assets.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/spec/dummy/config/initializers/backtrace_silencers.rb b/spec/dummy/config/initializers/backtrace_silencers.rb new file mode 100644 index 00000000..59385cdf --- /dev/null +++ b/spec/dummy/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/spec/dummy/config/initializers/content_security_policy.rb b/spec/dummy/config/initializers/content_security_policy.rb new file mode 100644 index 00000000..d3bcaa5e --- /dev/null +++ b/spec/dummy/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy +# For further information see the following documentation +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + +# Rails.application.config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https + +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end + +# If you are using UJS then enable automatic nonce generation +# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } + +# Report CSP violations to a specified URI +# For further information see the following documentation: +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only +# Rails.application.config.content_security_policy_report_only = true diff --git a/spec/dummy/config/initializers/cookies_serializer.rb b/spec/dummy/config/initializers/cookies_serializer.rb new file mode 100644 index 00000000..5a6a32d3 --- /dev/null +++ b/spec/dummy/config/initializers/cookies_serializer.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Specify a serializer for the signed and encrypted cookie jars. +# Valid options are :json, :marshal, and :hybrid. +Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/spec/dummy/config/initializers/filter_parameter_logging.rb b/spec/dummy/config/initializers/filter_parameter_logging.rb new file mode 100644 index 00000000..4a994e1e --- /dev/null +++ b/spec/dummy/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Configure sensitive parameters which will be filtered from the log file. +Rails.application.config.filter_parameters += [:password] diff --git a/spec/dummy/config/initializers/inflections.rb b/spec/dummy/config/initializers/inflections.rb new file mode 100644 index 00000000..ac033bf9 --- /dev/null +++ b/spec/dummy/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym 'RESTful' +# end diff --git a/spec/dummy/config/initializers/mime_types.rb b/spec/dummy/config/initializers/mime_types.rb new file mode 100644 index 00000000..dc189968 --- /dev/null +++ b/spec/dummy/config/initializers/mime_types.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf diff --git a/spec/dummy/config/initializers/wrap_parameters.rb b/spec/dummy/config/initializers/wrap_parameters.rb new file mode 100644 index 00000000..bbfc3961 --- /dev/null +++ b/spec/dummy/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# To enable root element in JSON for ActiveRecord objects. +# ActiveSupport.on_load(:active_record) do +# self.include_root_in_json = true +# end diff --git a/spec/dummy/config/locales/en.yml b/spec/dummy/config/locales/en.yml new file mode 100644 index 00000000..decc5a85 --- /dev/null +++ b/spec/dummy/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t 'hello' +# +# In views, this is aliased to just `t`: +# +# <%= t('hello') %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# 'true': 'foo' +# +# To learn more, please read the Rails Internationalization guide +# available at http://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/spec/dummy/config/puma.rb b/spec/dummy/config/puma.rb new file mode 100644 index 00000000..a5eccf81 --- /dev/null +++ b/spec/dummy/config/puma.rb @@ -0,0 +1,34 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked webserver processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. +# +# preload_app! + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/spec/dummy/config/routes.rb b/spec/dummy/config/routes.rb new file mode 100644 index 00000000..787824f8 --- /dev/null +++ b/spec/dummy/config/routes.rb @@ -0,0 +1,3 @@ +Rails.application.routes.draw do + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html +end diff --git a/spec/dummy/config/storage.yml b/spec/dummy/config/storage.yml new file mode 100644 index 00000000..d32f76e8 --- /dev/null +++ b/spec/dummy/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/spec/dummy/lib/assets/.keep b/spec/dummy/lib/assets/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/dummy/log/.keep b/spec/dummy/log/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/dummy/package.json b/spec/dummy/package.json new file mode 100644 index 00000000..caa2d7bb --- /dev/null +++ b/spec/dummy/package.json @@ -0,0 +1,5 @@ +{ + "name": "dummy", + "private": true, + "dependencies": {} +} diff --git a/spec/dummy/public/404.html b/spec/dummy/public/404.html new file mode 100644 index 00000000..2be3af26 --- /dev/null +++ b/spec/dummy/public/404.html @@ -0,0 +1,67 @@ + + + + The page you were looking for doesn't exist (404) + + + + + + +
+
+

The page you were looking for doesn't exist.

+

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

+
+

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

+
+ + diff --git a/spec/dummy/public/422.html b/spec/dummy/public/422.html new file mode 100644 index 00000000..c08eac0d --- /dev/null +++ b/spec/dummy/public/422.html @@ -0,0 +1,67 @@ + + + + The change you wanted was rejected (422) + + + + + + +
+
+

The change you wanted was rejected.

+

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

+
+

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

+
+ + diff --git a/spec/dummy/public/500.html b/spec/dummy/public/500.html new file mode 100644 index 00000000..78a030af --- /dev/null +++ b/spec/dummy/public/500.html @@ -0,0 +1,66 @@ + + + + We're sorry, but something went wrong (500) + + + + + + +
+
+

We're sorry, but something went wrong.

+
+

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

+
+ + diff --git a/spec/dummy/public/apple-touch-icon-precomposed.png b/spec/dummy/public/apple-touch-icon-precomposed.png new file mode 100644 index 00000000..e69de29b diff --git a/spec/dummy/public/apple-touch-icon.png b/spec/dummy/public/apple-touch-icon.png new file mode 100644 index 00000000..e69de29b diff --git a/spec/dummy/public/favicon.ico b/spec/dummy/public/favicon.ico new file mode 100644 index 00000000..e69de29b diff --git a/spec/dummy/spec/rails_helper.rb b/spec/dummy/spec/rails_helper.rb new file mode 100644 index 00000000..bbe1ba57 --- /dev/null +++ b/spec/dummy/spec/rails_helper.rb @@ -0,0 +1,57 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +require 'spec_helper' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +# Checks for pending migrations and applies them before tests are run. +# If you are not using ActiveRecord, you can remove this line. +ActiveRecord::Migration.maintain_test_schema! + +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, :type => :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/dummy/spec/spec_helper.rb b/spec/dummy/spec/spec_helper.rb new file mode 100644 index 00000000..75cc2ced --- /dev/null +++ b/spec/dummy/spec/spec_helper.rb @@ -0,0 +1,100 @@ +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = "doc" + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/spec/dummy/storage/.keep b/spec/dummy/storage/.keep new file mode 100644 index 00000000..e69de29b diff --git a/spec/features/asset_spec.rb b/spec/features/asset_spec.rb new file mode 100644 index 00000000..9d3b64af --- /dev/null +++ b/spec/features/asset_spec.rb @@ -0,0 +1,61 @@ +############################################### +############################################### +## ___ _ ## +## / _ \ | | ## +## / /_\ \___ ___ ___| |_ ___ ## +## | _ / __/ __|/ _ \ __/ __| ## +## | | | \__ \__ \ __/ |_\__ \ ## +## \_| |_/___/___/\___|\__|___/ ## +## ## +############################################### +############################################### + +require 'spec_helper' + +############################################### +############################################### + +# => ExceptionHandler (Assets) +# => Needs to test if exception_handler.css added to precompile queue +# => Needs to test if exception_handler.css adds /images folder +# => Needsd to check if all files are precompiled +RSpec.describe "ExceptionHandler Assets" do + + # => Defs + let(:assets) { Rails.configuration.assets } + let(:sprockets) { Rails.application.assets } + + # => Precompilation + # => Expects exception_handler.css + # => Expects contents of /images to be included by file + describe "precompile" do + subject { assets.precompile } + it { should include('exception_handler.css') } + end + + # => Images + # => Should be present in Rails.application.assets + # => ref: https://stackoverflow.com/a/11005361/1143732 + describe "images" do + it "includes exception_handler/images/*" do + #Dir.foreach('../../../app/assets/images') do |item| + # next if item == '.' or item == '..' + # puts item + # expect(sprockets.each_file).to include(item) + #end + end + end + + # => Assets + # => Expects exception_handler.css + # => Expects /images + # => Expects /images/[specific] + describe "assets" do + #it { expect(Rails.application.assets.find_asset(path)).to include('exception_handler.css') } + end + + +end + +############################################### +############################################### diff --git a/spec/features/config_spec.rb b/spec/features/config_spec.rb new file mode 100644 index 00000000..315f5642 --- /dev/null +++ b/spec/features/config_spec.rb @@ -0,0 +1,51 @@ +############################################### +############################################### +## _____ __ _ ## +## / __ \ / _(_) ## +## | / \/ ___ _ __ | |_ _ __ _ ## +## | | / _ \| '_ \| _| |/ _` | ## +## | \__/\ (_) | | | | | | | (_| | ## +## \____/\___/|_| |_|_| |_|\__, | ## +## __/ | ## +## |___/ ## +############################################### +############################################### + +require 'spec_helper' + +############################################### +############################################### + +# => ExceptionHandler (Config) +# => Should explore config has been created/initialized +# => Needs to identify available options (dev/db/email/social/layouts/exceptions/custom_exceptions) +# => Needs to return specific results per option (dev = true/false, email = string etc) +RSpec.describe ExceptionHandler.config do + + # => Config + let(:config) { ExceptionHandler.config } + + # => Class + # => Initialized? + # => Responds to methods? + describe "class" do + subject { config } + it { should be_a ExceptionHandler::Config } + %i(dev db email social layouts exceptions custom_exceptions).each do |method| + it { should respond_to(method) } + end + end + + # => Dev + # => true/false + describe "dev" do + subject { ExceptionHandler.config.dev } + #it { should be_boolean } + end + + # => DB + +end + +############################################### +############################################### diff --git a/spec/features/engine_spec.rb b/spec/features/engine_spec.rb new file mode 100644 index 00000000..35afcada --- /dev/null +++ b/spec/features/engine_spec.rb @@ -0,0 +1,180 @@ +############################################### +############################################### +## _____ _____ ## +## | ___ \/ ___| ## +## | |_/ /\ `--. _ __ ___ ___ ## +## | / `--. \ '_ \ / _ \/ __| ## +## | |\ \ /\__/ / |_) | __/ (__ ## +## \_| \_|\____/| .__/ \___|\___| ## +## | | ## +## |_| ## +############################################### +############################################### + +require 'spec_helper' + +############################################### +############################################### + +# => ExceptionHandler (base) +# => Test underlying engine (loading, initializers, etc) +# => Ensure that all elements are correctly integrated into Rails core +RSpec.describe ExceptionHandler::Engine do + + ############################################# + ############################################# + + # => Ensure Gem has value, loaded etc + describe "Gem" do + + # => Options + let(:version) { ExceptionHandler::VERSION::STRING } + let(:engine) { ExceptionHandler::Engine } + + # => Version needs to exist + # => Present Version + describe "version" do + subject { version } + it { is_expected.not_to be_empty } + it { is_expected.to eq('0.8.0.0') } + end + + # => Loaded? + # => Accessible by Rails? + describe "class" do + subject { engine } + it { should be_const_defined('ExceptionHandler') } + it { } + end + + end + + ############################################# + ############################################# + + # => Ensure Gem's features are loaded into Rails + describe "Setup" do + + ######################### + ######################### + + # => Options + let(:config) { ExceptionHandler.config } + let(:rails) { Rails.configuration } + + # => Before + before(:context) { ExceptionHandler.config.dev = false } + + ######################### + ######################### + + # => Config + # => Exists? Accessible? Right Values? + describe "config" do + subject { config } + + # => Initialized + it "has an initializer" do + expect(Rails.application.initializers.map(&:name)).to include(:exception_handler_config) + end + + # => Initialization Queue + it "is initialized before better_errors" do + end + + # => Accessible? + # => Can we access the instance of the class and see which items are available? + it { should be_a ExceptionHandler::Config } + it "is accessible" do + + end + + # => Values + # => The returned values need to be tested in the config class + it "responds to methods" do + %i(dev db email social layouts exceptions custom_exceptions).each do |method| + expect(config).to respond_to(method) + end + end + + # => Basic values + it "has basic values" do + expect(config.dev).to be_boolean + end + end + + ######################### + ######################### + + # => Middleware + # => Check if it's correctly overwritten @exceptions_app + # => http://guides.rubyonrails.org/configuring.html#rails-general-configuration + describe "middleware" do + subject { rails.exceptions_app } + #it { should eq(ExceptionHandler) } + # => accessible? + end + + ######################### + ######################### + + # => Dev Mode + # => Changes "consider_all_requests_local" to opposite of config + describe "dev" do + + # => Access dev mode + # => Ensure the config is present & accessible + context "config" do + subject { config.dev } + it { should_not be true } + end + + # => Local Requests + # => Should be the opposite of the dev option + context "local requests" do + subject { rails.consider_all_requests_local } + it { should_not be ExceptionHandler.config.dev } + end + + end + + ######################### + ######################### + + # => Custom Exceptions + # => Ensure custom exceptions added to Rails + describe "custom exceptions" do + + # => Rescue Response + subject { rails.action_dispatch.rescue_responses } + + # => Let + let(:config) { ExceptionHandler.config } + + # => Removes + it "has an initializer" do + expect(Rails.application.initializers.map(&:name)).to include(:exception_handler_custom_exceptions) + end + + # => Check if present + context "present" do + end + + # => Check if can be accessed + context "accessiblity" do + before { config.custom_exceptions.merge! 'ActionController::RoutingError' => :not_found } + + #it { should include config.custom_exceptions } + end + + end + + end + + ############################################# + ############################################# + +end + +############################################### +############################################### diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb new file mode 100644 index 00000000..0562e905 --- /dev/null +++ b/spec/routing/routing_spec.rb @@ -0,0 +1,85 @@ +############################################### +############################################### +## _____ _ ## +## | ___ \ | | ## +## | |_/ /___ _ _| |_ ___ ___ ## +## | // _ \| | | | __/ _ \/ __| ## +## | |\ \ (_) | |_| | || __/\__ \ ## +## \_| \_\___/ \__,_|\__\___||___/ ## +## ## +############################################### +############################################### + +require 'spec_helper' + +############################################### +############################################### + +# => Routes (base) +# => Test underlying routes + engine routes +RSpec.describe 'ExceptionHandler::Engine.routes' do + + ############################################# + ############################################# + + # => Let (config) + let(:dev) { ExceptionHandler.config.dev } + + ############################################# + ############################################# + + # => Rails application Routes + # => Should be routable WITH dev option + # => Should not be routable WITHOUT dev option + ['Rails.application.routes', 'ExceptionHandler::Engine.routes'].each do |item| + + # => Different types of route + # => Shouldn't have any routes for engine + context item do + + # => Routes + routes { eval item } + + # => Dev mode + context "✔️ dev mode" do + subject { dev } + before { ExceptionHandler.config.dev = true } + before { Rails.application.reload_routes! } + + it { should eq(true) } + it "has exception routes" do + Rack::Utils::SYMBOL_TO_STATUS_CODE.select{ |key, value| value.to_s.match('\b(?:4[0-9]{2}|5[0-9]{2}|599)\b') }.each do |status,code| + if item == 'Rails.application.routes' + expect(:get => code.to_s).to route_to(:controller => "exception_handler/exceptions", :action => "show", :code => status.to_sym) + else + expect(:get => code.to_s).not_to be_routable + end + end + end + + end + + # => Non Dev mode + context "❌ dev mode" do + subject { dev } + before { ExceptionHandler.config.dev = false } + before { Rails.application.reload_routes! } + + it { should_not eq(true) } + it "does not have exception routes" do + Rack::Utils::SYMBOL_TO_STATUS_CODE.select{ |key, value| value.to_s.match('\b(?:4[0-9]{2}|5[0-9]{2}|599)\b') }.each do |status,code| + expect(:get => code.to_s).not_to be_routable + end + end + + end + end + end + + ############################################# + ############################################# + +end + +############################################### +############################################### diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 00000000..10c1565d --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,93 @@ +############################################### +############################################### +## _____ _____ ## +## | ___ \/ ___| ## +## | |_/ /\ `--. _ __ ___ ___ ## +## | / `--. \ '_ \ / _ \/ __| ## +## | |\ \ /\__/ / |_) | __/ (__ ## +## \_| \_|\____/| .__/ \___|\___| ## +## | | ## +## |_| ## +############################################### +############################################### + +# => Helper +require 'spec_helper' + +# => ENV +ENV["RAILS_ENV"] ||= "test" + +# => Rails +require_relative './dummy/config/environment' +abort("The Rails environment is running in production mode!") if Rails.env.production? + +# => RSpec +require 'rspec/rails' + +# => Environment +ActiveRecord::Migrator.migrations_paths = [File.expand_path("./dummy/db/migrate", __dir__)] + +# => Gem (to test) +require 'exception_handler' + +############################################### +############################################### + +# => ActiveRecord +ActiveRecord::Migration.maintain_test_schema! + +# Load fixtures from the engine +if ActiveSupport::TestCase.respond_to?(:fixture_path=) + ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) + ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path + ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" + ActiveSupport::TestCase.fixtures :all +end + +############################################### +############################################### + +#=> Custom Matchers +RSpec::Matchers.define :be_boolean do + match do |value| + [true, false].include? value + end +end + +############################################### +############################################### + +# => http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + expectations.syntax = :expect + end + + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + # Disable RSpec exposing methods globally on `Module` and `main` + config.disable_monkey_patching! + + # => Rails (Fixtures etc) + config.infer_spec_type_from_file_location! + config.filter_rails_from_backtrace! + config.order = :random + + # => Asset Precompile + config.before(:suite) do + Rails.application.load_tasks + Rake::Task["assets:precompile"].invoke + end + + config.after(:suite) do + Rails.application.load_tasks + Rake::Task["assets:clobber"].invoke + end + +end diff --git a/spec/views/views_spec.rb b/spec/views/views_spec.rb new file mode 100644 index 00000000..1b470ba7 --- /dev/null +++ b/spec/views/views_spec.rb @@ -0,0 +1,29 @@ +############################################### +############################################### +## _ _ _ ## +## | | | (_) ## +## | | | |_ _____ _____ ## +## | | | | |/ _ \ \ /\ / / __| ## +## \ \_/ / | __/\ V V /\__ \ ## +## \___/|_|\___| \_/\_/ |___/ ## +## ## +############################################### +############################################### + +require 'spec_helper' + +############################################### +############################################### + +# => ExceptionHandler (Views) +# => Determine views / layout for different exceptions +# => Needs to explain exactly what users is doing to see (request.status, message etc) +# => Needs to include 404/500 dev routes +RSpec.describe "ExceptionHandler Views" do + + + +end + +############################################### +###############################################