restful_error 1.0.4 → 1.0.5

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: cf170d758ce3175fe4b56ec695fbf4be09569474e66b376df7395084b8babda5
4
- data.tar.gz: df9042f7e3a5ab6d80b7c861e61f35604f894715226c2b2b87bd4ccbff610ad9
3
+ metadata.gz: ed208c312dae52e3f02f31f16ee66ebe34b6a98f02195c6dae1178c8ae638aab
4
+ data.tar.gz: f28848072ce6af1819ccefce94b474c11d5eb92543698f5fb4478d80984cc6a4
5
5
  SHA512:
6
- metadata.gz: 1b649d3d114cfc2dfb0eefd9c96a0e69be07715d3e2c9517dda75b0d80ad0d08e05f07ed968ecb5f74bb51da4b3d68dfdc512097d78c5d030a9343b16d922ad6
7
- data.tar.gz: b9440442b318f6d64958c14e0252d26a628cb8545c03d716464f10493e016c9a6848b1636dd6f0321b0bcf605833e3bc20db0188da6096d64177f390a47f896b
6
+ metadata.gz: 833c5516e492850176e4321769fd2eb4060036b2948c9a9bcbbe40bace7c082bb4f473879713c02ba55a204509214bd57f50963128a384e16db23586c710519a
7
+ data.tar.gz: ed25e5a04a3ddb4761449d034b2457097c7d7aa2a4a684dfcaa9a4dccd211c9baecd7d54e1dc3460fac03501eb8a49c5ed32751a6bc96f6353336e7fa2f67e4e
data/README.md CHANGED
@@ -16,41 +16,65 @@ And then execute:
16
16
 
17
17
  ## Usage
18
18
 
19
- ### Pure ruby
19
+ ### Pure ruby (without Rails)
20
+ #### Predefined errors
20
21
  ```ruby
21
22
  ex = RestfulError[404].new
22
- ex.restful.code # => 404
23
- ex.restful.reason_phrase # => "Not Found"
23
+
24
+ StandardError === ex # => true # because inherit from StandardError
25
+ RestfulError::BaseError === ex # => true
26
+
27
+ RestfulError[404] == RestfulError::NotFound # => true # same class
28
+
29
+ ex.status_data # returns Data about status code
30
+ # => #<data RestfulError::Status
31
+ # code=404,
32
+ # reason_phrase="Not Found",
33
+ # symbol=:not_found,
34
+ # const_name="NotFound">
35
+ ex.status_data.code # => 404
24
36
  ```
25
37
 
26
- #### your custom error by subclassing
38
+ #### Custom error by subclassing
27
39
  ```ruby
28
40
  class ::NoSession < RestfulError[404]; end
29
41
  # or
30
42
  class ::NoSession < RestfulError::NotFound; end
31
43
  ```
32
- #### your custom error with http_status
33
- ```ruby
34
- class OAuthController < ApplicationController
35
44
 
36
- # define http_status and include RestfulError::Helper
37
- class PermissionError < StandardError
38
- include RestfulError::Helper
39
- def http_status = 401
40
- end
41
- # or
42
- class PermissionError < StandardError
43
- include RestfulError::Helper
44
- def http_status; :unauthorized; end
45
- end
45
+ #### Custom error with http_status
46
+ ```ruby
47
+ # define http_status and include RestfulError::Helper
48
+ class User::PermissionError < StandardError
49
+ include RestfulError::Helper
50
+ def http_status = :unauthorized # or 401
46
51
  end
47
- PermissionError.new.restful.reason_phrase # => "Unauthorized"
52
+ User::PermissionError.new.status_data.reason_phrase # => "Unauthorized"
53
+ ```
54
+
55
+ ### With I18n
56
+ `#response_message` returns i18nized message.
57
+ ```yaml
58
+ ja:
59
+ restful_error:
60
+ unauthorized: ログインが必要です
61
+ not_found: ページが存在しません
62
+ user/permission_error: 権限がありません
63
+ ```
64
+ ```ruby
65
+ # lookup class name first, then status symbol
66
+ User::PermissionError.new.response_message # => "権限がありません"
67
+ AnotherPermissionError.new.response_message # => "ログインが必要です"
48
68
  ```
49
69
 
50
70
  ### With Rails
51
- `config.exceptions_app` will automatically set.
71
+ `config.exceptions_app` will automatically set to RestfulError::ExceptionsApp.
72
+
73
+ If you want to disable it, you have two options.
74
+ - `config.restful_error.exceptions_app.enable = false` (will not set exceptions_app)
75
+ - `config.exceptions_app = ActionDispatch::PublicExceptions.new(Rails.public_path)` (set Rails default explicitly, or set your own)
52
76
 
53
- #### raise me in request
77
+ #### Raise me in request handling
54
78
  ```ruby
55
79
  class PostsController < ApplicationController
56
80
  before_action do
@@ -62,58 +86,43 @@ end
62
86
  ```
63
87
 
64
88
 
65
- #### Multi format response
89
+ #### Render response
90
+ Default view files are in https://github.com/kuboon/restful_error/tree/main/app/views/restful_error
66
91
 
67
- ```ruby
68
- get '/posts/new'
69
- #=> render 'restful_error/show.html' with @status_code and @message
92
+ `html`, `json` and `xml` are supported.
70
93
 
71
- post '/posts.json'
72
- #=> { status_code: 401, message: "Sign in required" } or write your json at 'restful_error/show.json'
94
+ You can override them by creating view file `show.{format}.{handler}` under your `app/views/restful_error/` directory.
73
95
 
74
- get '/session.xml'
75
- #=> "<error><status_code type="integer">401</status_code><message>Sign in required</message></error>" or write your xml at 'restful_error/show.xml'
76
- ```
96
+ `@status` `@status_code` `@reason_phrase` `@response_message` are available in the view.
77
97
 
78
- #### I18n
98
+ If you have `layouts/restful_error.*.*`, or `layouts/application.*.*`, it will be used as layout. This is done by inheriting `::ApplicationController`.
79
99
 
80
- ```yaml
81
- ja:
82
- restful_error:
83
- unauthorized: ログインしてください #401
84
- not_found: ページが存在しません #404
85
- ```
100
+ To change superclass,
101
+ set `config.restful_error.exceptions_app.inherit_from = 'AnotherBaseController'`
86
102
 
87
- #### library defined error
88
- ``` ruby
89
- config.action_dispatch.rescue_responses["CanCan::Unauthorized"] = 401
90
- # or
91
- config.action_dispatch.rescue_responses["CanCan::Unauthorized"] = :unauthorized
103
+ #### Library defined error
104
+ You can assign status code to error classes which are not yours. (This is Rails standard)
105
+
106
+ ```ruby
107
+ config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :unauthorized # or 401
92
108
  ```
93
- #### I18n
109
+
110
+ RestfulError will use this configuration to lookup status code and
111
+ `@response_message` will be set.
112
+
94
113
  ```yaml
95
114
  ja:
96
115
  restful_error:
97
- no_session: セッションがありません
98
- oauth_controller/require_twitter_login: Twitterログインが必要です
99
- can_can/unauthorized: 権限がありません
116
+ pundit/not_authorized_error: アクセス権限がありません
100
117
  active_record/record_not_found: 要求されたリソースが存在しません
101
118
  ```
102
- #### custom message
103
119
 
104
- ```ruby
105
- class RequireLogin < StandardError
106
- def initialize(provider = 'Unknown')
107
- @provider = provider
108
- end
109
- def status_code
110
- :unauthorized
111
- end
112
- def response_message
113
- I18n.t('restful_error.require_login', provider: provider)
114
- end
115
- end
116
- ```
120
+ ## Why `response_message`, not `message`?
121
+ `StandardError#message` is used for debugging purpose, not intended to be shown to users.
122
+ Rails default behavior does not show `message` in production environment. So I decided to use `response_message` instead.
123
+
124
+ You can `def response_message` or set `@resposne_message` in your error class to build dynamic message.
125
+
117
126
 
118
127
  ## Contributing
119
128
 
@@ -0,0 +1,5 @@
1
+ <html>
2
+ <body>
3
+ <%= yield %>
4
+ </body>
5
+ </html>
@@ -0,0 +1,5 @@
1
+ raw JSON.generate(
2
+ status_code: @status_code,
3
+ reason_phrase: @reason_phrase,
4
+ response_message: @response_message
5
+ )
@@ -0,0 +1,11 @@
1
+ require "abstract_controller"
2
+ require "action_controller/metal"
3
+
4
+ module RestfulError
5
+ class ApplicationController < ::ActionController::Metal
6
+ abstract!
7
+ include AbstractController::Rendering
8
+ include ActionView::Layouts
9
+ include ActionController::Rendering
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ require "abstract_controller"
2
+ require "action_controller/metal"
3
+
4
+ module RestfulError
5
+ class ExceptionsApp
6
+ Config = Struct.new(:enable, :inherit_from, :fallback)
7
+ def self.config
8
+ @config ||= Config.new.tap do |config|
9
+ config.enable = true
10
+ config.inherit_from = "::ApplicationController"
11
+ end
12
+ end
13
+
14
+ def initialize(config = self.class.config)
15
+ @config = config
16
+ end
17
+ def call(env)
18
+ app.call(env)
19
+ rescue Exception => _e
20
+ raise unless @config.fallback
21
+ @config.fallback.call(env)
22
+ end
23
+
24
+ private
25
+
26
+ def app
27
+ @app ||= begin
28
+ # To use "layouts/application" we need inherit from ::ApplicationController
29
+ # It is not defined at config time, so we need to load it here
30
+ if @config.inherit_from && Object.const_defined?(@config.inherit_from)
31
+ inherit_from = @config.inherit_from.constantize
32
+ else
33
+ inherit_from = RestfulError::ApplicationController
34
+ end
35
+ const_set_without_warn(RestfulError, "SuperController", inherit_from)
36
+ ExceptionsController.action(:show)
37
+ end
38
+ end
39
+ def const_set_without_warn(klass, const_name, value)
40
+ klass.send(:remove_const, const_name) if klass.const_defined?(const_name)
41
+ klass.const_set(const_name, value)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,19 @@
1
+ module RestfulError
2
+ class ExceptionsController < SuperController
3
+ def self.controller_path = "restful_error"
4
+ append_view_path File.join(File.dirname(__FILE__), "../../app/views")
5
+
6
+ layout nil
7
+
8
+ def show
9
+ @exception = request.env["action_dispatch.exception"]
10
+ code = request.path_info[1..].to_i
11
+ status = RestfulError.build_status_from_symbol_or_code(code)
12
+ @status_code = status.code
13
+ @reason_phrase = status.reason_phrase
14
+ @response_message = @exception.try(:response_message) || RestfulError.localized_phrase(@exception.class.name, status) || nil
15
+
16
+ render status: status.code, formats: request.format.symbol
17
+ end
18
+ end
19
+ end
@@ -1,27 +1,15 @@
1
- require "abstract_controller"
2
- require "action_controller/metal"
1
+ require "restful_error/exceptions_app"
3
2
 
4
3
  module RestfulError
5
- class ExceptionsController < ::ActionController::Metal
6
- include AbstractController::Rendering
7
- include ActionView::Layouts
8
-
9
- append_view_path File.join(File.dirname(__FILE__), "../../app/views")
10
-
11
- def show
12
- @exception = request.env["action_dispatch.exception"]
13
- code = request.path_info[1..].to_i
14
- status = RestfulError.build_status_from_symbol_or_code(code)
15
- @status_code = status.code
16
- @reason_phrase = status.reason_phrase
17
- @response_message = @exception.try(:response_message) || RestfulError.localized_phrase(@exception.class.name, status) || nil
18
-
19
- self.status = status.code
20
- render "restful_error/show", formats: request.format.symbol
4
+ class Railtie < Rails::Railtie
5
+ config.restful_error = ActiveSupport::OrderedOptions.new
6
+ config.restful_error.exceptions_app = RestfulError::ExceptionsApp.config
7
+
8
+ initializer "restful_error.exceptions_app", before: :build_middleware_stack do |app|
9
+ if app.config.restful_error.exceptions_app.enable
10
+ app.config.restful_error.exceptions_app.fallback ||= ActionDispatch::PublicExceptions.new(Rails.public_path)
11
+ app.config.exceptions_app ||= RestfulError::ExceptionsApp.new
12
+ end
21
13
  end
22
14
  end
23
-
24
- def self.exceptions_app
25
- ExceptionsController.action(:show)
26
- end
27
15
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RestfulError
4
- VERSION = "1.0.4"
4
+ VERSION = "1.0.5"
5
5
  end
data/lib/restful_error.rb CHANGED
@@ -1,29 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rack/utils"
4
- require "restful_error/railtie" if defined? ActionController
5
4
  require "restful_error/status"
6
5
  require "restful_error/version"
6
+ require "restful_error/railtie" if defined? Rails::Railtie
7
7
 
8
8
  module RestfulError
9
+ autoload :ExceptionsApp, "restful_error/exceptions_app"
10
+ autoload :ApplicationController, "restful_error/application_controller"
11
+ autoload :ExceptionsController, "restful_error/exceptions_controller"
12
+
9
13
  module Helper
10
- def restful
11
- @restful ||= begin
12
- raise NotImplementedError, "http_status must be implemented by including class" unless respond_to?(:http_status)
13
- RestfulError.build_status_from_symbol_or_code(http_status)
14
- end
14
+ def status_data
15
+ @status_data ||= RestfulError.build_status_from_symbol_or_code(http_status)
15
16
  end
16
17
  def response_message
17
18
  return @response_message unless @response_message.nil?
18
- @response_message = RestfulError.localized_phrase(self.class.name, restful)
19
+ @response_message = RestfulError.localized_phrase(self.class.name, status_data)
19
20
  end
20
21
  end
21
22
 
22
23
  class BaseError < StandardError
23
24
  include RestfulError::Helper
24
- def initialize(message = nil)
25
- @response_message = message
26
- super
25
+ def http_status
26
+ raise NotImplementedError, "http_status must be implemented"
27
27
  end
28
28
  end
29
29
 
@@ -58,7 +58,7 @@ module RestfulError
58
58
  def build_error_class_for(status)
59
59
  klass = Class.new(BaseError) do
60
60
  define_method(:http_status) { status.code }
61
- define_method(:restful) { status }
61
+ define_method(:status_data) { status }
62
62
  end
63
63
  const_set(status.const_name, klass)
64
64
  if defined? ActionDispatch::ExceptionWrapper
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restful_error
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - kuboon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-31 00:00:00.000000000 Z
11
+ date: 2025-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -40,12 +40,16 @@ extra_rdoc_files: []
40
40
  files:
41
41
  - LICENSE.txt
42
42
  - README.md
43
+ - app/views/layouts/application.html.erb
43
44
  - app/views/restful_error/show.html.erb
44
- - app/views/restful_error/show.json.erb
45
+ - app/views/restful_error/show.json.ruby
45
46
  - app/views/restful_error/show.xml.erb
46
47
  - config/locales/en.restful_error.yml
47
48
  - config/locales/ja.restful_error.yml
48
49
  - lib/restful_error.rb
50
+ - lib/restful_error/application_controller.rb
51
+ - lib/restful_error/exceptions_app.rb
52
+ - lib/restful_error/exceptions_controller.rb
49
53
  - lib/restful_error/inflector.rb
50
54
  - lib/restful_error/railtie.rb
51
55
  - lib/restful_error/status.rb
@@ -1,7 +0,0 @@
1
- <%=
2
- raw JSON.generate(
3
- status_code: @status_code,
4
- reason_phrase: @reason_phrase,
5
- response_message: @response_message
6
- )
7
- %>