exception_handler 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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 %>