exception_handler 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +4 -4
  4. data/Gemfile +1 -3
  5. data/README.md +111 -98
  6. data/app/assets/images/exception_handler/connect/facebook.png +0 -0
  7. data/app/assets/images/exception_handler/connect/fusion.png +0 -0
  8. data/app/assets/images/exception_handler/connect/linkedin.png +0 -0
  9. data/app/assets/images/exception_handler/connect/twitter.png +0 -0
  10. data/app/assets/images/exception_handler/connect/youtube.png +0 -0
  11. data/app/assets/images/exception_handler/noise.png +0 -0
  12. data/app/assets/images/favicon.ico +0 -0
  13. data/app/assets/stylesheets/exception_handler.css.erb +18 -0
  14. data/app/assets/stylesheets/styles/_base.css.erb +34 -0
  15. data/app/assets/stylesheets/styles/_exception.css.erb +105 -0
  16. data/app/assets/stylesheets/styles/_footer.css.erb +27 -0
  17. data/app/assets/stylesheets/styles/_responsive.css +5 -0
  18. data/app/controllers/exception_handler/exception_controller.rb +28 -33
  19. data/app/mailers/exception_handler/exception_mailer.rb +17 -0
  20. data/app/models/exception_handler/exception.rb +191 -0
  21. data/app/views/exception_handler/exception/show.html.erb +3 -32
  22. data/app/views/exception_handler/mailers/layout.haml +8 -0
  23. data/app/views/exception_handler/mailers/layout.text.erb +1 -0
  24. data/app/views/exception_handler/mailers/new_exception.erb +4 -0
  25. data/app/views/layouts/exception.html.erb +15 -23
  26. data/config/locales/exception_handler.en.yml +13 -0
  27. data/exception_handler.gemspec +61 -16
  28. data/lib/exception_handler.rb +20 -79
  29. data/lib/exception_handler/config.rb +20 -22
  30. data/lib/exception_handler/engine.rb +36 -0
  31. data/lib/generators/exception_handler/migration_generator.rb +28 -10
  32. data/lib/generators/exception_handler/views_generator.rb +5 -5
  33. data/lib/generators/templates/migration.rb.erb +12 -11
  34. metadata +41 -64
  35. data/app/assets/images/exception_handler/close.png +0 -0
  36. data/app/assets/images/exception_handler/home.png +0 -0
  37. data/app/assets/stylesheets/exception_handler/error.css.erb +0 -309
  38. data/app/helpers/exception_handler/application_helper.rb +0 -56
  39. data/app/models/exception_handler/error.rb +0 -14
  40. data/app/services/exception_handler/exception.rb +0 -34
  41. data/config/locales/en.yml +0 -9
  42. data/lib/exception_handler/parse.rb +0 -23
  43. data/lib/exception_handler/parser/data.rb +0 -59
  44. data/lib/exception_handler/parser/ignore.rb +0 -32
  45. data/lib/exception_handler/version.rb +0 -3
  46. data/post_install_message.md +0 -53
  47. data/spec/helpers/exception_handler/application_helper_spec.rb +0 -42
@@ -0,0 +1,105 @@
1
+ /* ---------------------------------------------------- */
2
+ /* ---------------------------------------------------- */
3
+
4
+ .exception {
5
+ display: block;
6
+ color: #fff;
7
+ position: relative;
8
+ width: 30%;
9
+ top: 48%;
10
+ margin: auto;
11
+ background: rgba(255,255,255,0.15);
12
+ border: 1px solid rgba(0,0,0,1);
13
+ max-width: 450px;
14
+ min-width: 350px;
15
+ font-size: 0.85em;
16
+ border-radius: 5px;
17
+ box-sizing: border-box;
18
+ box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.8);
19
+ background-clip: border-box;
20
+ text-shadow: 0 1px 0 rgba(0,0,0,1);
21
+ overflow-x: hidden;
22
+ overflow-y: hidden;
23
+ transition: background 0.1s ease-in-out;
24
+ transform: translateY(-50%);
25
+ }
26
+ .exception::before {
27
+ content: attr(data-status) " Error (" attr(data-response) ") …";
28
+ display: block;
29
+ color: #fff;
30
+ font-size: 1.75em;
31
+ font-weight: bold;
32
+ text-transform: capitalize;
33
+ background-color: rgba(227,11,11,1);
34
+ padding: 1em;
35
+ box-sizing: border-box;
36
+ background-color: rgba(227,11,11,1);
37
+
38
+ border-bottom: 1px solid rgba(227,11,11,0.35);
39
+
40
+ background-image: url(<%= asset_url("exception_handler/noise.png") %>), -moz-linear-gradient(top, rgba(227,11,11,0) 0%, rgba(0,0,0,0.55) 100%); /* FF3.6+ */
41
+ background-image: url(<%= asset_url("exception_handler/noise.png") %>), -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(227,11,11,0)), color-stop(100%,rgba(0,0,0,0.55))); /* Chrome,Safari4+ */
42
+ background-image: url(<%= asset_url("exception_handler/noise.png") %>), -webkit-linear-gradient(top, rgba(227,11,11,0) 0%,rgba(0,0,0,0.55) 100%); /* Chrome10+,Safari5.1+ */
43
+ background-image: url(<%= asset_url("exception_handler/noise.png") %>), -o-linear-gradient(top, rgba(227,11,11,0) 0%,rgba(0,0,0,0.55) 100%); /* Opera 11.10+ */
44
+ background-image: url(<%= asset_url("exception_handler/noise.png") %>), -ms-linear-gradient(top, rgba(227,11,11,0) 0%,rgba(0,0,0,0.55) 100%); /* IE10+ */
45
+ background-image: url(<%= asset_url("exception_handler/noise.png") %>), linear-gradient(to bottom, rgba(227,11,11,0) 0%,rgba(0,0,0,0.55) 100%); /* W3C */
46
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#007a07ed', endColorstr='#000000',GradientType=0 ); /* IE6-9 */
47
+ }
48
+ .exception::after {
49
+ content: attr(data-rails) " \203A\203A Our developers have been notified. Click here to go home.";
50
+ display: block;
51
+ padding: 1em;
52
+ font-size: 0.9em;
53
+ background: rgba(0,0,0,0.5);
54
+ }
55
+ .exception:hover { cursor: pointer; }
56
+
57
+ .exception span:before {
58
+ display: block;
59
+ content: url(<%= asset_url("exception_handler/alert.png") %>);
60
+ padding: 5em 0;
61
+ text-align: center;
62
+ }
63
+ .exception span:after {
64
+ content: "";
65
+ display: block;
66
+ position: absolute;
67
+ left: 0;
68
+ top: 0;
69
+ width: 100%;
70
+ height: 2px;
71
+
72
+ background: rgba(0,0,0,0.35);
73
+ background: -moz-linear-gradient(top, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
74
+ background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(0,0,0,0.35)), color-stop(100%, rgba(0,0,0,0)));
75
+ background: -webkit-linear-gradient(top, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
76
+ background: -o-linear-gradient(top, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
77
+ background: -ms-linear-gradient(top, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
78
+ background: linear-gradient(to bottom, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
79
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#000000', endColorstr='#000000', GradientType=0 );
80
+ }
81
+ .exception span {
82
+ position: relative;
83
+ display: block;
84
+ min-height: 288px;
85
+ padding: 0 2em 3.5em;
86
+ box-sizing: border-box;
87
+ background: #000 url(<%= asset_url("exception_handler/alert.jpg") %>) top center no-repeat;
88
+ background-size: cover;
89
+ text-align: center;
90
+
91
+ border-width: 0 1px;
92
+ border-style: solid;
93
+ border-color: rgba(255,255,255,0.065);
94
+ }
95
+ .exception span strong {
96
+ display: block;
97
+ margin-bottom: 0.5em;
98
+ margin-top: 0.25em;
99
+ font-size: 1.95em;
100
+ text-transform: uppercase;
101
+ text-decoration: underline;
102
+ }
103
+
104
+ /* ---------------------------------------------------- */
105
+ /* ---------------------------------------------------- */
@@ -0,0 +1,27 @@
1
+ /* ---------------------------------------------------- */
2
+ /* ---------------------------------------------------- */
3
+
4
+ footer {
5
+ display: block;
6
+ position: absolute;
7
+ bottom: 0;
8
+ width: 100%;
9
+ opacity: 0.75;
10
+ font-size: 2em;
11
+ text-align: center;
12
+ vertical-align: middle;
13
+ transition: opacity 0.15s ease-in-out;
14
+ }
15
+ footer:hover { opacity: 1; }
16
+ footer a {
17
+ display: inline-block;
18
+ opacity: 0.45;
19
+ margin-right: -4px;
20
+ padding: 1.5em 0.3em;
21
+ transition: opacity 0.15s ease-in-out;
22
+ }
23
+ footer a:hover { opacity: 1; text-decoration: none; }
24
+ footer a img { width: 24px; vertical-align: middle; }
25
+
26
+ /* ---------------------------------------------------- */
27
+ /* ---------------------------------------------------- */
@@ -0,0 +1,5 @@
1
+ /* Responsive */
2
+ @media screen and (max-width: 950px) {
3
+ html { background-size: cover !important; }
4
+ .container .error { width: 55% !important; }
5
+ }
@@ -1,50 +1,45 @@
1
1
  module ExceptionHandler
2
2
  class ExceptionController < ApplicationController
3
3
 
4
- #Response
5
- #http://www.justinweiss.com/articles/respond-to-without-all-the-pain/
4
+ # => Response
5
+ # => http://www.justinweiss.com/articles/respond-to-without-all-the-pain/
6
6
  respond_to :html, :xml, :json
7
7
 
8
- #Layout
9
- layout :layout
10
-
11
- #Helpers
12
- helper ExceptionHandler::Engine.helpers #-> HELPERS http://stackoverflow.com/questions/9809787/why-is-my-rails-mountable-engine-not-loading-helper-methods-correctly
13
- include Rails.application.routes.url_helpers #-> ROUTES http://stackoverflow.com/a/6074911/1143732
14
-
15
- ####################
16
- # Action #
17
- ####################
18
-
19
- #Show
20
- #Amend responses in tests
21
- #Need to test validity of JSON responses etc
22
- def show
23
- @exception = ExceptionHandler::Exception.new request #-> Service Object
24
- render status: @exception.status #-> Show apppropriate response
25
- end
8
+ ##################################
9
+ ##################################
26
10
 
27
- ####################
28
- # Dependencies #
29
- ####################
11
+ # => Definitions
12
+ # => Exception model (tied to DB)
13
+ before_action { |e| @exception = ExceptionHandler::Exception.new request: e.request }
14
+ before_action { @exception.save if @exception.valid? && ExceptionHandler.config.try(:db) }
30
15
 
31
- protected
16
+ # => Routes
17
+ # => Removes need for "main_app" prefix in routes
18
+ # => http://stackoverflow.com/a/40251516/1143732
19
+ helper Rails.application.routes.url_helpers
32
20
 
33
- # Status declarations moved to "show" w/ service object
34
- # Details moved to "View Helper"
21
+ # => Layout
22
+ # => Layouts only 400 / 500 because they are the only error responses (300 is redirect)
23
+ # => http://guides.rubyonrails.org/layouts_and_rendering.html#the-status-option
24
+ # => Layout proc kills inheritance, needs to be method for now
25
+ layout :layout
35
26
 
36
27
  ####################
37
- # Layout #
28
+ # Action #
38
29
  ####################
39
30
 
40
- private
41
-
42
- #Layout
43
- def layout
44
- (/^(5[0-9]{2})$/ !~ @exception.code.to_s) ? (ExceptionHandler.config.layouts["400"] || nil) : ExceptionHandler.config.layouts["500"] #-> if not 500, use predefined layout
31
+ def show
32
+ respond_with @exception, status: @exception.status
45
33
  end
46
34
 
47
- ####################
35
+ ##################################
36
+ ##################################
37
+
38
+ private
39
+
40
+ def layout
41
+ ExceptionHandler.config.layouts[ @exception.status[0] + "00" ]
42
+ end
48
43
 
49
44
  end
50
45
  end
@@ -0,0 +1,17 @@
1
+ module ExceptionHandler
2
+ class ExceptionMailer < ActionMailer::Base
3
+
4
+ # Layout
5
+ layout "mailers/layouts/mailer"
6
+
7
+ # Defaults
8
+ default from: ExceptionHandler.config.email
9
+ default template_path: "exception_handler/mailers" # => http://stackoverflow.com/a/18579046/1143732
10
+
11
+ def new_exception e
12
+ @exception = e
13
+ mail to: ExceptionHandler.config.email
14
+ Rails.logger.info "Exception Sent To → #{ExceptionHandler.config.email}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,191 @@
1
+ module ExceptionHandler
2
+
3
+ ############################################################
4
+ ############################################################
5
+
6
+ # => Search Bots
7
+ # => Used in "Exception" class
8
+ BOTS = %w(Baidu Gigabot Googlebot libwww-per lwp-trivial msnbot SiteUptime Slurp Wordpress ZIBB ZyBorg Yandex Jyxobot Huaweisymantecspider ApptusBot)
9
+
10
+ # => Attributes
11
+ # => Determine schema size etc
12
+ ATTRS = %i(class_name status message trace target referrer params user_agent)
13
+
14
+ ############################################################
15
+ ############################################################
16
+
17
+ # => Class (inheritance dependent on whether db option is available)
18
+ self::Exception = Class.new (ExceptionHandler.config.try(:db) ? ActiveRecord::Base : Object) do
19
+
20
+ # => Include individual elements
21
+ # => Only required if no db present (no ActiveRecord)
22
+ if ExceptionHandler.config.try(:db)
23
+
24
+ # => Set Attrs
25
+ def initialize attributes={}
26
+ super
27
+ ATTRS.each do |type|
28
+ self[type] = eval type.to_s
29
+ end
30
+ end
31
+
32
+ else
33
+
34
+ # => AciveModel
35
+ include ActiveModel::Model
36
+ include ActiveModel::Validations
37
+
38
+ # => Callback Extension
39
+ extend ActiveModel::Callbacks
40
+ define_model_callbacks :initialize, only: :after
41
+
42
+ # => Initialize
43
+ # => http://api.rubyonrails.org/classes/ActiveModel/Callbacks.html
44
+ # => http://stackoverflow.com/a/17682228/1143732
45
+ def initialize attributes={}
46
+ super
47
+ run_callbacks :initialize do
48
+ # => Needed for after_initialize
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ ##################################
55
+ ##################################
56
+
57
+ ####################
58
+ # Table #
59
+ ####################
60
+
61
+ # Schema
62
+ ###################
63
+ # class_name @exception.class.name
64
+ # status ActionDispatch::ExceptionWrapper.new(@request.env, @exception).status_code
65
+ # message @exception.message
66
+ # trace @exception.backtrace.join("\n")
67
+ # target @request.url
68
+ # referer @request.referer
69
+ # params @request.params.inspect
70
+ # user_agent @request.user_agent
71
+ # created_at
72
+ # updated_at
73
+
74
+ # => Table is called "errors"
75
+ # => Dev needs to use migration to create db
76
+ if ExceptionHandler.config.try(:db)
77
+ def self.table_name
78
+ ExceptionHandler.config.db
79
+ end
80
+ end
81
+
82
+ ##################################
83
+ ##################################
84
+
85
+ ####################
86
+ # Options #
87
+ ####################
88
+
89
+ # => Email
90
+ # => after_initialize invoked after .new method called
91
+ # => Should have been after_create but user may not save
92
+ after_initialize Proc.new { |e| ExceptionHandler::ExceptionMailer.new_exception(e).deliver } if ExceptionHandler.config.try(:email) && ExceptionHandler.config.email.is_a?(String)
93
+
94
+ # => Attributes
95
+ attr_accessor :request, :klass, :exception, :description
96
+ attr_accessor *ATTRS unless ExceptionHandler.config.try(:db)
97
+
98
+ # => Validations
99
+ validates :klass, exclusion: { in: [ActionController::RoutingError, AbstractController::ActionNotFound, ActiveRecord::RecordNotFound], message: "%{value}" }, if: "referer.blank?"
100
+ validates :user_agent, format: { without: Regexp.new( BOTS.join("|"), Regexp::IGNORECASE ) }
101
+
102
+ ##################################
103
+ ##################################
104
+
105
+ ####################################
106
+ # Virtual
107
+ ####################################
108
+
109
+ # => Klass
110
+ # => Used for validation (needs to be cleaned up in 0.7.0)
111
+ def klass
112
+ exception.class
113
+ end
114
+
115
+ # => Exception (virtual)
116
+ def exception
117
+ request.env['action_dispatch.exception']
118
+ end
119
+
120
+ # => Description
121
+ def description
122
+ I18n.with_options scope: [:exception], message: message do |i18n|
123
+ i18n.t response, default: status
124
+ end
125
+ end
126
+
127
+ ####################################
128
+ # Exception
129
+ ####################################
130
+
131
+ # => Class Name
132
+ def class_name
133
+ exception.class.name
134
+ end
135
+
136
+ # => Message
137
+ def message
138
+ exception.message
139
+ end
140
+
141
+ # => Trace
142
+ def trace
143
+ exception.backtrace.join("\n")
144
+ end
145
+
146
+ ####################################
147
+ # Request
148
+ ####################################
149
+
150
+ # => Target URL
151
+ def target
152
+ request.url
153
+ end
154
+
155
+ # => Referrer URL
156
+ def referer
157
+ request.referer
158
+ end
159
+
160
+ # => Params
161
+ def params
162
+ request.params.inspect
163
+ end
164
+
165
+ # => User Agent
166
+ def user_agent
167
+ request.user_agent
168
+ end
169
+
170
+ ####################################
171
+ # Other
172
+ ####################################
173
+
174
+ # => Status code (404, 500 etc)
175
+ def status
176
+ ActionDispatch::ExceptionWrapper.new(request.env, exception).status_code.to_s
177
+ end
178
+
179
+ # => Server Response ("Not Found" etc)
180
+ def response
181
+ ActionDispatch::ExceptionWrapper.rescue_responses[class_name]
182
+ end
183
+
184
+ ##################################
185
+ ##################################
186
+
187
+ end
188
+ end
189
+
190
+ ############################################################
191
+ ############################################################
@@ -1,32 +1,3 @@
1
- <div class="error">
2
- <% if /^(5[0-9]{2})$/ =~ @exception.status.to_s %>
3
-
4
- <!--Message -->
5
- <%= content_tag :div, class: "message" do %>
6
- <%= content_tag :div, class: "title" do %>
7
- <span><%= "#{@exception.status} Error - #{details[:name]}" %></span>
8
- <%= link_to image_tag("exception_handler/close.png"), main_app.root_url, title: "Close (Go back home)", class: "close" %>
9
- <% end %>
10
-
11
- <%= content_tag :div, class: "details" do %>
12
- <%= image_tag "exception_handler/alert.png", title: "#{@exception.status} Error" %>
13
- <div class="status"><%= @exception.status %> Error</div>
14
- <% end %>
15
-
16
- <%= content_tag :div, class: "info" do %>
17
- <span><%= details[:description] %></span>
18
- <div class="notification">
19
- <%= link_to image_tag("exception_handler/home.png", title: "Go Back Home"), main_app.root_url, class: "home" %>
20
- <div class="version">v<%= Rails.version %></div>
21
- <strong>Our developers have been notified - we're working on it!</strong>
22
- </div>
23
- <% end %>
24
-
25
- <% end %>
26
-
27
- <% else %>
28
-
29
- <%= content_tag :div, details[:description], class: "message" %>
30
-
31
- <% end %>
32
- </div>
1
+ <%= content_tag :div, class: "exception", data: { status: @exception.status, response: @exception.response.to_s.humanize, rails: Rails.version }, onclick: "location.href=\"#{root_url}\";" do %>
2
+ <%= content_tag :span, @exception.description.html_safe %>
3
+ <% end %>