forked from richpeck/exception_handler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
exception.rb
199 lines (157 loc) · 6.04 KB
/
exception.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
module ExceptionHandler
############################################################
############################################################
# => Search Bots
# => Used in "Exception" class
BOTS = %w(Baidu Gigabot Googlebot libwww-per lwp-trivial msnbot SiteUptime Slurp Wordpress ZIBB ZyBorg Yandex Jyxobot Huaweisymantecspider ApptusBot)
# => 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
# => Include individual elements
# => Only required if no db present (no ActiveRecord)
if ExceptionHandler.config.try(:db)
# => Set Attrs
def initialize attributes={}
super
ATTRS.each do |type|
self[type] = eval type.to_s
end
end
else
# => ActiveModel
include ActiveModel::Model
include ActiveModel::Validations
# => Callback Extension
extend ActiveModel::Callbacks
define_model_callbacks :initialize, only: :after
# => Initialize
# => http://api.rubyonrails.org/classes/ActiveModel/Callbacks.html
# => http://stackoverflow.com/a/17682228/1143732
def initialize attributes={}
super
run_callbacks :initialize do
# => Needed for after_initialize
end
end
end
##################################
##################################
####################
# Table #
####################
# Schema
###################
# class_name @exception.class.name
# status ActionDispatch::ExceptionWrapper.new(@request.env, @exception).status_code
# message @exception.message
# trace @exception.backtrace.join("\n")
# target @request.url
# referer @request.referer
# params @request.params.inspect
# user_agent @request.user_agent
# created_at
# updated_at
# => Table is called "errors"
# => Dev needs to use migration to create db
if ExceptionHandler.config.try(:db)
def self.table_name
ExceptionHandler.config.db
end
end
##################################
##################################
####################
# Options #
####################
# => 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)
# => 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 ) }
##################################
##################################
####################################
# Virtual
####################################
# => 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
end
end
####################################
# Exception
####################################
# => Class Name
def class_name
exception.class.name
end
# => Message
def message
exception.message
end
# => Trace
def trace
exception.backtrace.join("\n")
end
####################################
# Request
####################################
# => Target URL
def target
request.url
end
# => Referrer URL
def referer
request.referer
end
# => Params
def params
request.params.inspect
end
# => User Agent
def user_agent
request.user_agent
end
####################################
# Other
####################################
# => Status code (404, 500 etc)
def status
ActionDispatch::ExceptionWrapper.new(request.env, exception).status_code
end
# => Server Response ("Not Found" etc)
def response
ActionDispatch::ExceptionWrapper.rescue_responses[class_name]
end
##################################
##################################
end
end
############################################################
############################################################