better_errors 2.5.1 → 2.8.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 949ae4930972ea12a576bf6036ab19ef6f9d876c03a640062f76a0871648181f
4
- data.tar.gz: 36dcea704937546ac60e4d0c9503222fbcd0cb0aa62e6b2b2e35d92b8cbbbc2c
3
+ metadata.gz: 59e37a4996e35b2775a359cbe11302a8ded7213d7e940905a92cfe39d872e2e9
4
+ data.tar.gz: f162b4cbb8d5fc3c285c466ecbfb449626337e724cd0c8964fcbc7fb3784288b
5
5
  SHA512:
6
- metadata.gz: 5bc9b0ea98c35285ad19a774394b26459c80cda362b3fd940c490c4342e8190550990615c04bad077b5f71adb6e609caf890027baf8832c8de287713dcb0ca90
7
- data.tar.gz: e0f31fa9e3dfa676e35a6838547280df6da65573a14d55da125d0d20dc62edaef8485cd30e2580f50bff26d82d6533167453ee3e941cf7697ac3b6e423994b40
6
+ metadata.gz: 36a80fb99501720b6dda49b61dac22deefa30b9bfcc46b7c00c7ec293dc0de4400dcdb4ac3b35d46d3d6722d8bf79a5e7ace2481c3c91ad1b0310900135aa802
7
+ data.tar.gz: 3d3c7f3eea41454551f3fa21dd8721da779eaa676f97520946fcb8294e20c3bdddb88fd613bfd43cdf0edaf434583c8c93ddc3ad099fddc8e8179598c70b9e92
@@ -1,16 +1,5 @@
1
- sudo: false
2
1
  language: ruby
3
2
  cache: bundler
4
- before_install:
5
- # Since Rails 4.2 only supports rubygems < 2, we must install an older version for it.
6
- - >
7
- if [[ "$BUNDLE_GEMFILE" =~ "rails42" ]]; then
8
- rvm @global do gem install rubygems-update -v '<2'
9
- update_rubygems
10
- rvm @global do gem uninstall bundler --force --executables
11
- rvm @global do gem install bundler -v "~> 1.3"
12
- fi
13
-
14
3
  notifications:
15
4
  webhooks:
16
5
  # With COVERALLS_PARALLEL, coverage information sent to coveralls will not be processed until
@@ -19,23 +8,29 @@ notifications:
19
8
  - secure: "YnHYbTq51ySistjvOxsuNhyg4GLuUffEJstTYeGYXiBF7HG5h43IVYo8KNuLzwkgsOYBcNo+YMdQX7qCqJffSbhsr1FZRSzBmjFFxcyD4hu+ukM2theZ4mePVAZiePscYvQPRNY4hIb4d3egStJEytkalDhB3sOebF57tIaCssg="
20
9
  rvm:
21
10
  - 2.2.10
22
- - 2.3.7
23
- - 2.4.4
24
- - 2.5.1
11
+ - 2.3.8
12
+ - 2.4.9
13
+ - 2.5.7
14
+ - 2.6.5
15
+ - 2.7.0
25
16
  - ruby-head
17
+ - truffleruby-head
26
18
  gemfile:
27
19
  - gemfiles/rails42.gemfile
28
20
  - gemfiles/rails50.gemfile
29
21
  - gemfiles/rails51.gemfile
30
22
  - gemfiles/rails52.gemfile
23
+ - gemfiles/rails60.gemfile
31
24
  - gemfiles/rails42_haml.gemfile
32
25
  - gemfiles/rails50_haml.gemfile
33
26
  - gemfiles/rails51_haml.gemfile
34
27
  - gemfiles/rails52_haml.gemfile
28
+ - gemfiles/rails60_haml.gemfile
35
29
  - gemfiles/rails42_boc.gemfile
36
30
  - gemfiles/rails50_boc.gemfile
37
31
  - gemfiles/rails51_boc.gemfile
38
32
  - gemfiles/rails52_boc.gemfile
33
+ - gemfiles/rails60_boc.gemfile
39
34
  - gemfiles/rack.gemfile
40
35
  - gemfiles/rack_boc.gemfile
41
36
  - gemfiles/pry09.gemfile
@@ -48,15 +43,69 @@ matrix:
48
43
  - gemfile: gemfiles/pry010.gemfile
49
44
  - gemfile: gemfiles/pry011.gemfile
50
45
  exclude:
51
- - rvm: 2.4.4
46
+ - rvm: 2.2.10
47
+ gemfile: gemfiles/rails60.gemfile
48
+ - rvm: 2.2.10
49
+ gemfile: gemfiles/rails60_boc.gemfile
50
+ - rvm: 2.2.10
51
+ gemfile: gemfiles/rails60_haml.gemfile
52
+ - rvm: 2.3.8
52
53
  gemfile: gemfiles/rails42.gemfile
53
- - rvm: 2.4.4
54
+ - rvm: 2.3.8
54
55
  gemfile: gemfiles/rails42_boc.gemfile
55
- - rvm: 2.4.4
56
+ - rvm: 2.3.8
56
57
  gemfile: gemfiles/rails42_haml.gemfile
57
- - rvm: 2.5.1
58
+ - rvm: 2.3.8
59
+ gemfile: gemfiles/rails60.gemfile
60
+ - rvm: 2.3.8
61
+ gemfile: gemfiles/rails60_boc.gemfile
62
+ - rvm: 2.3.8
63
+ gemfile: gemfiles/rails60_haml.gemfile
64
+ - rvm: 2.4.9
58
65
  gemfile: gemfiles/rails42.gemfile
59
- - rvm: 2.5.1
66
+ - rvm: 2.4.9
60
67
  gemfile: gemfiles/rails42_boc.gemfile
61
- - rvm: 2.5.1
68
+ - rvm: 2.4.9
62
69
  gemfile: gemfiles/rails42_haml.gemfile
70
+ - rvm: 2.4.9
71
+ gemfile: gemfiles/rails60.gemfile
72
+ - rvm: 2.4.9
73
+ gemfile: gemfiles/rails60_boc.gemfile
74
+ - rvm: 2.4.9
75
+ gemfile: gemfiles/rails60_haml.gemfile
76
+ - rvm: 2.5.7
77
+ gemfile: gemfiles/rails42.gemfile
78
+ - rvm: 2.5.7
79
+ gemfile: gemfiles/rails42_boc.gemfile
80
+ - rvm: 2.5.7
81
+ gemfile: gemfiles/rails42_haml.gemfile
82
+ - rvm: 2.6.5
83
+ gemfile: gemfiles/rails42.gemfile
84
+ - rvm: 2.6.5
85
+ gemfile: gemfiles/rails42_boc.gemfile
86
+ - rvm: 2.6.5
87
+ gemfile: gemfiles/rails42_haml.gemfile
88
+ - rvm: 2.7.0
89
+ gemfile: gemfiles/rails42.gemfile
90
+ - rvm: 2.7.0
91
+ gemfile: gemfiles/rails42_boc.gemfile
92
+ - rvm: 2.7.0
93
+ gemfile: gemfiles/rails42_haml.gemfile
94
+ - rvm: ruby-head
95
+ gemfile: gemfiles/rails42.gemfile
96
+ - rvm: ruby-head
97
+ gemfile: gemfiles/rails42_boc.gemfile
98
+ - rvm: ruby-head
99
+ gemfile: gemfiles/rails42_haml.gemfile
100
+ - rvm: truffleruby-head
101
+ gemfile: gemfiles/rails42_boc.gemfile
102
+ - rvm: truffleruby-head
103
+ gemfile: gemfiles/rails50_boc.gemfile
104
+ - rvm: truffleruby-head
105
+ gemfile: gemfiles/rails51_boc.gemfile
106
+ - rvm: truffleruby-head
107
+ gemfile: gemfiles/rails52_boc.gemfile
108
+ - rvm: truffleruby-head
109
+ gemfile: gemfiles/rails60_boc.gemfile
110
+ - rvm: truffleruby-head
111
+ gemfile: gemfiles/rack_boc.gemfile
data/README.md CHANGED
@@ -35,6 +35,28 @@ end
35
35
 
36
36
  _Note: If you discover that Better Errors isn't working - particularly after upgrading from version 0.5.0 or less - be sure to set `config.consider_all_requests_local = true` in `config/environments/development.rb`._
37
37
 
38
+ ### Optional: Set `EDITOR`
39
+
40
+ For many reasons outside of Better Errors, you should have the `EDITOR` environment variable set to your preferred
41
+ editor.
42
+ Better Errors, like many other tools, will use that environment variable to show a link that opens your
43
+ editor to the file and line from the console.
44
+
45
+ By default the links will open TextMate-protocol links.
46
+
47
+ To see if your editor is supported or to set up a different editor, see [the wiki](https://github.com/BetterErrors/better_errors/wiki/Link-to-your-editor).
48
+
49
+ ### Optional: Set `BETTER_ERRORS_INSIDE_FRAME`
50
+
51
+ If your application is running inside of an iframe, or if you have a Content Security Policy that disallows links
52
+ to other protocols, the editor links will not work.
53
+
54
+ To work around this set `BETTER_ERRORS_INSIDE_FRAME=1` in the environment, and the links will include `target=_blank`,
55
+ allowing the link to open regardless of the policy.
56
+
57
+ _This works because it opens the editor from a new browser tab, escaping from the restrictions of your site._
58
+ _Unfortunately it leaves behind an empty tab each time, so only use this if needed._
59
+
38
60
  ## Security
39
61
 
40
62
  **NOTE:** It is *critical* you put better\_errors only in the **development** section of your Gemfile.
@@ -93,6 +115,16 @@ See [the wiki for instructions on configuring the editor](https://github.com/Bet
93
115
  BetterErrors.maximum_variable_inspect_size = 100_000
94
116
  ```
95
117
 
118
+ ## Ignore inspection of variables with certain classes.
119
+
120
+ ```ruby
121
+ # e.g. in config/initializers/better_errors.rb
122
+ # This will stop BetterErrors from trying to inspect objects of these classes, which can cause
123
+ # slow loading times and unneccessary database queries. Does not check inheritance chain, use
124
+ # strings not contants.
125
+ # default value: ['ActionDispatch::Request', 'ActionDispatch::Response']
126
+ BetterErrors.ignored_classes = ['ActionDispatch::Request', 'ActionDispatch::Response']
127
+ ```
96
128
 
97
129
  ## Get in touch!
98
130
 
@@ -22,9 +22,11 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.add_development_dependency "rake", "~> 10.0"
24
24
  s.add_development_dependency "rspec", "~> 3.5"
25
+ s.add_development_dependency "rspec-html-matchers"
25
26
  s.add_development_dependency "rspec-its"
26
27
  s.add_development_dependency "yard"
27
- s.add_development_dependency "kramdown"
28
+ # kramdown 2.1 requires Ruby 2.3+
29
+ s.add_development_dependency "kramdown", (RUBY_VERSION < '2.3' ? '< 2.0.0' : '> 2.0.0')
28
30
  # simplecov and coveralls must not be included here. See the Gemfiles instead.
29
31
 
30
32
  s.add_dependency "erubi", ">= 1.0.0"
@@ -2,6 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 4.2.0"
4
4
  gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7'
5
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
6
 
6
7
  gem 'coveralls', require: false
7
8
 
@@ -2,6 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 4.2.0"
4
4
  gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7'
5
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
6
  gem "binding_of_caller"
6
7
 
7
8
  gem 'coveralls', require: false
@@ -2,6 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 4.2.0"
4
4
  gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7'
5
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
6
  gem "haml"
6
7
 
7
8
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.0.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
 
5
6
  gem 'coveralls', require: false
6
7
 
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.0.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "binding_of_caller"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.0.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "haml"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.1.0"
4
+ gem 'i18n', '< 1.5.2', require: false if RUBY_VERSION < '2.3'
4
5
 
5
6
  gem 'coveralls', require: false
6
7
 
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.1.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "binding_of_caller"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.1.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "haml"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.2.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
 
5
6
  gem 'coveralls', require: false
6
7
 
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.2.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "binding_of_caller"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.2.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "haml"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.0.0"
4
+
5
+ gem 'coveralls', require: false
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.0.0"
4
+ gem "binding_of_caller"
5
+
6
+ gem 'coveralls', require: false
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.0.0"
4
+ gem "haml"
5
+
6
+ gem 'coveralls', require: false
7
+
8
+ gemspec path: "../"
@@ -21,6 +21,7 @@ module BetterErrors
21
21
  { symbols: [:idea], sniff: /idea/i, url: "idea://open?file=%{file}&line=%{line}" },
22
22
  { symbols: [:rubymine], sniff: /mine/i, url: "x-mine://open?file=%{file}&line=%{line}" },
23
23
  { symbols: [:vscode, :code], sniff: /code/i, url: "vscode://file/%{file}:%{line}" },
24
+ { symbols: [:vscodium, :codium], sniff: /codium/i, url: "vscodium://file/%{file}:%{line}" },
24
25
  { symbols: [:atom], sniff: /atom/i, url: "atom://core/open/file?filename=%{file}&line=%{line}" },
25
26
  ]
26
27
 
@@ -54,9 +55,14 @@ module BetterErrors
54
55
  # the variable won't be returned.
55
56
  # @return int
56
57
  attr_accessor :maximum_variable_inspect_size
58
+
59
+ # List of classes that are excluded from inspection.
60
+ # @return [Array]
61
+ attr_accessor :ignored_classes
57
62
  end
58
63
  @ignored_instance_variables = []
59
64
  @maximum_variable_inspect_size = 100_000
65
+ @ignored_classes = ['ActionDispatch::Request', 'ActionDispatch::Response']
60
66
 
61
67
  # Returns a proc, which when called with a filename and line number argument,
62
68
  # returns a URL to open the filename and line in the selected editor.
@@ -26,8 +26,13 @@ module BetterErrors
26
26
  @id ||= SecureRandom.hex(8)
27
27
  end
28
28
 
29
- def render(template_name = "main")
29
+ def render(template_name = "main", csrf_token = nil)
30
30
  binding.eval(self.class.template(template_name).src)
31
+ rescue => e
32
+ # Fix the backtrace, which doesn't identify the template that failed (within Better Errors).
33
+ # We don't know the line number, so just injecting the template path has to be enough.
34
+ e.backtrace.unshift "#{self.class.template_path(template_name)}:0"
35
+ raise
31
36
  end
32
37
 
33
38
  def do_variables(opts)
@@ -59,7 +64,19 @@ module BetterErrors
59
64
  end
60
65
 
61
66
  def exception_message
62
- exception.message.lstrip
67
+ exception.message.strip.gsub(/(\r?\n\s*\r?\n)+/, "\n")
68
+ end
69
+
70
+ def active_support_actions
71
+ return [] unless defined?(ActiveSupport::ActionableError)
72
+
73
+ ActiveSupport::ActionableError.actions(exception.type)
74
+ end
75
+
76
+ def action_dispatch_action_endpoint
77
+ return unless defined?(ActionDispatch::ActionableExceptions)
78
+
79
+ ActionDispatch::ActionableExceptions.endpoint
63
80
  end
64
81
 
65
82
  def application_frames
@@ -105,7 +122,13 @@ module BetterErrors
105
122
  end
106
123
 
107
124
  def inspect_value(obj)
108
- InspectableValue.new(obj).to_html
125
+ if BetterErrors.ignored_classes.include? obj.class.name
126
+ "<span class='unsupported'>(Instance of ignored class. "\
127
+ "#{obj.class.name ? "Remove #{CGI.escapeHTML(obj.class.name)} from" : "Modify"}"\
128
+ " BetterErrors.ignored_classes if you need to see it.)</span>"
129
+ else
130
+ InspectableValue.new(obj).to_html
131
+ end
109
132
  rescue BetterErrors::ValueLargerThanConfiguredMaximum
110
133
  "<span class='unsupported'>(Object too large. "\
111
134
  "#{obj.class.name ? "Modify #{CGI.escapeHTML(obj.class.name)}#inspect or a" : "A"}"\
@@ -1,5 +1,6 @@
1
1
  require "json"
2
2
  require "ipaddr"
3
+ require "securerandom"
3
4
  require "set"
4
5
  require "rack"
5
6
 
@@ -33,12 +34,14 @@ module BetterErrors
33
34
  # Adds an address to the set of IP addresses allowed to access Better
34
35
  # Errors.
35
36
  def self.allow_ip!(addr)
36
- ALLOWED_IPS << IPAddr.new(addr)
37
+ ALLOWED_IPS << (addr.is_a?(IPAddr) ? addr : IPAddr.new(addr))
37
38
  end
38
39
 
39
40
  allow_ip! "127.0.0.0/8"
40
41
  allow_ip! "::1/128" rescue nil # windows ruby doesn't have ipv6 support
41
42
 
43
+ CSRF_TOKEN_COOKIE_NAME = 'BetterErrors-CSRF-Token'
44
+
42
45
  # A new instance of BetterErrors::Middleware
43
46
  #
44
47
  # @param app The Rack app/middleware to wrap with Better Errors
@@ -72,7 +75,7 @@ module BetterErrors
72
75
  def better_errors_call(env)
73
76
  case env["PATH_INFO"]
74
77
  when %r{/__better_errors/(?<id>.+?)/(?<method>\w+)\z}
75
- internal_call env, $~
78
+ internal_call(env, $~[:id], $~[:method])
76
79
  when %r{/__better_errors/?\z}
77
80
  show_error_page env
78
81
  else
@@ -89,11 +92,14 @@ module BetterErrors
89
92
  end
90
93
 
91
94
  def show_error_page(env, exception=nil)
95
+ request = Rack::Request.new(env)
96
+ csrf_token = request.cookies[CSRF_TOKEN_COOKIE_NAME] || SecureRandom.uuid
97
+
92
98
  type, content = if @error_page
93
99
  if text?(env)
94
100
  [ 'plain', @error_page.render('text') ]
95
101
  else
96
- [ 'html', @error_page.render ]
102
+ [ 'html', @error_page.render('main', csrf_token) ]
97
103
  end
98
104
  else
99
105
  [ 'html', no_errors_page ]
@@ -104,12 +110,22 @@ module BetterErrors
104
110
  status_code = ActionDispatch::ExceptionWrapper.new(env, exception).status_code
105
111
  end
106
112
 
107
- [status_code, { "Content-Type" => "text/#{type}; charset=utf-8" }, [content]]
113
+ response = Rack::Response.new(content, status_code, { "Content-Type" => "text/#{type}; charset=utf-8" })
114
+
115
+ unless request.cookies[CSRF_TOKEN_COOKIE_NAME]
116
+ response.set_cookie(CSRF_TOKEN_COOKIE_NAME, value: csrf_token, httponly: true, same_site: :strict)
117
+ end
118
+
119
+ # In older versions of Rack, the body returned here is actually a Rack::BodyProxy which seems to be a bug.
120
+ # (It contains status, headers and body and does not act like an array of strings.)
121
+ # Since we already have status code and body here, there's no need to use the ones in the Rack::Response.
122
+ (_status_code, headers, _body) = response.finish
123
+ [status_code, headers, [content]]
108
124
  end
109
125
 
110
126
  def text?(env)
111
127
  env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" ||
112
- !env["HTTP_ACCEPT"].to_s.include?('html')
128
+ !env["HTTP_ACCEPT"].to_s.include?('html')
113
129
  end
114
130
 
115
131
  def log_exception
@@ -129,13 +145,22 @@ module BetterErrors
129
145
  end
130
146
  end
131
147
 
132
- def internal_call(env, opts)
148
+ def internal_call(env, id, method)
149
+ return not_found_json_response unless %w[variables eval].include?(method)
133
150
  return no_errors_json_response unless @error_page
134
- return invalid_error_json_response if opts[:id] != @error_page.id
151
+ return invalid_error_json_response if id != @error_page.id
152
+
153
+ request = Rack::Request.new(env)
154
+ return invalid_csrf_token_json_response unless request.cookies[CSRF_TOKEN_COOKIE_NAME]
155
+
156
+ request.body.rewind
157
+ body = JSON.parse(request.body.read)
158
+ return invalid_csrf_token_json_response unless request.cookies[CSRF_TOKEN_COOKIE_NAME] == body['csrfToken']
159
+
160
+ return not_acceptable_json_response unless request.content_type == 'application/json'
135
161
 
136
- env["rack.input"].rewind
137
- response = @error_page.send("do_#{opts[:method]}", JSON.parse(env["rack.input"].read))
138
- [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(response)]]
162
+ response = @error_page.send("do_#{method}", body)
163
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(response)]]
139
164
  end
140
165
 
141
166
  def no_errors_page
@@ -157,18 +182,40 @@ module BetterErrors
157
182
  "The application has been restarted since this page loaded, " +
158
183
  "or the framework is reloading all gems before each request "
159
184
  end
160
- [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(
185
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
161
186
  error: 'No exception information available',
162
187
  explanation: explanation,
163
188
  )]]
164
189
  end
165
190
 
166
191
  def invalid_error_json_response
167
- [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(
192
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
168
193
  error: "Session expired",
169
194
  explanation: "This page was likely opened from a previous exception, " +
170
195
  "and the exception is no longer available in memory.",
171
196
  )]]
172
197
  end
198
+
199
+ def invalid_csrf_token_json_response
200
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
201
+ error: "Invalid CSRF Token",
202
+ explanation: "The browser session might have been cleared, " +
203
+ "or something went wrong.",
204
+ )]]
205
+ end
206
+
207
+ def not_found_json_response
208
+ [404, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
209
+ error: "Not found",
210
+ explanation: "Not a recognized internal call.",
211
+ )]]
212
+ end
213
+
214
+ def not_acceptable_json_response
215
+ [406, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
216
+ error: "Request not acceptable",
217
+ explanation: "The internal request did not match an acceptable content type.",
218
+ )]]
219
+ end
173
220
  end
174
221
  end
@@ -4,9 +4,18 @@ module BetterErrors
4
4
  attr_reader :exception, :message, :backtrace
5
5
 
6
6
  def initialize(exception)
7
- if exception.respond_to?(:cause)
7
+ if exception.class.name == "ActionView::Template::Error" && exception.respond_to?(:cause)
8
+ # Rails 6+ exceptions of this type wrap the "real" exception, and the real exception
9
+ # is actually more useful than the ActionView-provided wrapper. Once Better Errors
10
+ # supports showing all exceptions in the cause stack, this should go away. Or perhaps
11
+ # this can be changed to provide guidance by showing the second error in the cause stack
12
+ # under this condition.
8
13
  exception = exception.cause if exception.cause
9
14
  elsif exception.respond_to?(:original_exception) && exception.original_exception
15
+ # This supports some specific Rails exceptions, and this is not intended to act the same as
16
+ # the Ruby's {Exception#cause}.
17
+ # It's possible this should only support ActionView::Template::Error, but by not changing
18
+ # this we're preserving longstanding behavior of Better Errors with Rails < 6.
10
19
  exception = exception.original_exception
11
20
  end
12
21
 
@@ -36,8 +45,13 @@ module BetterErrors
36
45
 
37
46
  def setup_backtrace_from_bindings
38
47
  @backtrace = exception.__better_errors_bindings_stack.map { |binding|
39
- file = binding.eval "__FILE__"
40
- line = binding.eval "__LINE__"
48
+ if binding.respond_to?(:source_location) # Ruby >= 2.6
49
+ file = binding.source_location[0]
50
+ line = binding.source_location[1]
51
+ else
52
+ file = binding.eval "__FILE__"
53
+ line = binding.eval "__LINE__"
54
+ end
41
55
  name = binding.frame_description
42
56
  StackFrame.new(file, line, name, binding)
43
57
  }
@@ -69,7 +69,10 @@ module BetterErrors
69
69
  def local_variables
70
70
  return {} unless frame_binding
71
71
 
72
- frame_binding.eval("local_variables").each_with_object({}) do |name, hash|
72
+ lv = frame_binding.eval("local_variables")
73
+ return {} unless lv
74
+
75
+ lv.each_with_object({}) do |name, hash|
73
76
  # Ruby 2.2's local_variables will include the hidden #$! variable if
74
77
  # called from within a rescue context. This is not a valid variable name,
75
78
  # so the local_variable_get method complains. This should probably be
@@ -94,7 +97,10 @@ module BetterErrors
94
97
  end
95
98
 
96
99
  def visible_instance_variables
97
- frame_binding.eval("instance_variables") - BetterErrors.ignored_instance_variables
100
+ iv = frame_binding.eval("instance_variables")
101
+ return {} unless iv
102
+
103
+ iv - BetterErrors.ignored_instance_variables
98
104
  end
99
105
 
100
106
  def to_s
@@ -146,6 +146,14 @@
146
146
  }
147
147
 
148
148
  /* Heading */
149
+ header.exception .fix-actions {
150
+ margin-top: .5em;
151
+ }
152
+
153
+ header.exception .fix-actions input[type=submit] {
154
+ font-weight: bold;
155
+ }
156
+
149
157
  header.exception h2 {
150
158
  font-weight: 200;
151
159
  font-size: 11pt;
@@ -153,7 +161,7 @@
153
161
 
154
162
  header.exception h2,
155
163
  header.exception p {
156
- line-height: 1.4em;
164
+ line-height: 1.5em;
157
165
  overflow: hidden;
158
166
  white-space: pre;
159
167
  text-overflow: ellipsis;
@@ -166,7 +174,7 @@
166
174
 
167
175
  header.exception p {
168
176
  font-weight: 200;
169
- font-size: 20pt;
177
+ font-size: 17pt;
170
178
  color: white;
171
179
  }
172
180
 
@@ -744,6 +752,18 @@
744
752
  <header class="exception">
745
753
  <h2><strong><%= exception_type %></strong> <span>at <%= request_path %></span></h2>
746
754
  <p><%= exception_message %></p>
755
+ <% unless active_support_actions.empty? %>
756
+ <div class='fix-actions'>
757
+ <% active_support_actions.each do |action, _| %>
758
+ <form class="button_to" method="post" action="<%= action_dispatch_action_endpoint %>">
759
+ <input type="submit" value="<%= action %>">
760
+ <input type="hidden" name="action" value="<%= action %>">
761
+ <input type="hidden" name="error" value="<%= exception_type %>">
762
+ <input type="hidden" name="location" value="<%= request_path %>">
763
+ </form>
764
+ <% end %>
765
+ </div>
766
+ <% end %>
747
767
  </header>
748
768
  </div>
749
769
 
@@ -780,6 +800,7 @@
780
800
  (function() {
781
801
 
782
802
  var OID = "<%= id %>";
803
+ var csrfToken = "<%= csrf_token %>";
783
804
 
784
805
  var previousFrame = null;
785
806
  var previousFrameInfo = null;
@@ -790,6 +811,7 @@
790
811
  var req = new XMLHttpRequest();
791
812
  req.open("POST", "//" + window.location.host + <%== uri_prefix.gsub("<", "&lt;").inspect %> + "/__better_errors/" + OID + "/" + method, true);
792
813
  req.setRequestHeader("Content-Type", "application/json");
814
+ opts.csrfToken = csrfToken;
793
815
  req.send(JSON.stringify(opts));
794
816
  req.onreadystatechange = function() {
795
817
  if(req.readyState == 4) {
@@ -1,7 +1,14 @@
1
1
  <header class="trace_info clearfix">
2
2
  <div class="title">
3
3
  <h2 class="name"><%= @frame.name %></h2>
4
- <div class="location"><span class="filename"><a href="<%= editor_url(@frame) %>"><%= @frame.pretty_path %></a></span></div>
4
+ <div class="location">
5
+ <span class="filename">
6
+ <a
7
+ href="<%= editor_url(@frame) %>"
8
+ <%= ENV.key?('BETTER_ERRORS_INSIDE_FRAME') ? "target=_blank" : '' %>
9
+ ><%= @frame.pretty_path %></a>
10
+ </span>
11
+ </div>
5
12
  </div>
6
13
  <div class="code_block clearfix">
7
14
  <%== html_formatted_code_block @frame %>
@@ -1,3 +1,3 @@
1
1
  module BetterErrors
2
- VERSION = "2.5.1"
2
+ VERSION = "2.8.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.1
4
+ version: 2.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charlie Somerville
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-14 00:00:00.000000000 Z
11
+ date: 2020-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.5'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec-its
42
+ name: rspec-html-matchers
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: yard
56
+ name: rspec-its
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: kramdown
70
+ name: yard
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: kramdown
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">"
88
+ - !ruby/object:Gem::Version
89
+ version: 2.0.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.0.0
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: erubi
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -157,6 +171,9 @@ files:
157
171
  - gemfiles/rails52.gemfile
158
172
  - gemfiles/rails52_boc.gemfile
159
173
  - gemfiles/rails52_haml.gemfile
174
+ - gemfiles/rails60.gemfile
175
+ - gemfiles/rails60_boc.gemfile
176
+ - gemfiles/rails60_haml.gemfile
160
177
  - lib/better_errors.rb
161
178
  - lib/better_errors/code_formatter.rb
162
179
  - lib/better_errors/code_formatter/html.rb
@@ -197,7 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
197
214
  - !ruby/object:Gem::Version
198
215
  version: '0'
199
216
  requirements: []
200
- rubygems_version: 3.0.1
217
+ rubygems_version: 3.1.2
201
218
  signing_key:
202
219
  specification_version: 4
203
220
  summary: Better error page for Rails and other Rack apps