belt 0.6.0 → 0.6.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: 62b1b84b58bb017a4a127a871136dfc32b02217314bf5fc5f2b1baceb599063b
4
- data.tar.gz: 2bd29c90f7380f4efa4014cc079fefacef86ed9407b19f71fb06fc0ead217bff
3
+ metadata.gz: 66c35b71a47f74ba7805bce24b37eb02fa6ded7246872df30a951a35be22d21f
4
+ data.tar.gz: 5ddc3bb756fdf782da5074abb72bd0c7275c6a90f4ba98c81963b92cb9cd6bb9
5
5
  SHA512:
6
- metadata.gz: be2982d7fc1cc0bbac0a61369029801e2c95ccbb3539ca2effaa649f506cbda151d0e1b4f55284534a30d13331e36c7c215236eef5f5417c288bf282757d0afb
7
- data.tar.gz: ab198a8c848feb617046b1dbe73d5887252253617da7420ecd5935a56925bd18473430dbf2f54b5f9302e7c9bee777f21416b19ea28ac37d8bdc377aa6730222
6
+ metadata.gz: 44320ad96e29e29a6bb9b88d2de94822f982dad01e92bc639204c38d2bb7a306463b7b570ac8c35cbf13cc00a223a55442b52171ac64f3357de98a9662a5e3e9
7
+ data.tar.gz: 8e176982bec58892623685d2b3bfd02cde1ab22d9fcac2c6eb1bfe58f5ae27f02d28b708cced560b803379b36bcd2bea5463fce749bde4ebd9b169cbfff878ba
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.1
4
+
5
+ ### Fixed
6
+
7
+ - **`before_action` now halts the request when it produces a response.** The docs said
8
+ a callback could halt by calling `error_response`, but `dispatch` ignored callback
9
+ output and ran the action anyway, so the action's response replaced the error. A
10
+ guard like `error_response('Forbidden', 403) unless admin?` let everyone through.
11
+ Now, once a callback calls a response helper (`error_response`, `success_response`,
12
+ `html_response`, `head`, `render`) or returns a response, the remaining callbacks, the
13
+ action and the `after_action`s are skipped and that response is returned
14
+ (Rails-style). Apps that worked around this with inline guards in each action keep
15
+ working; the inline checks are now redundant.
16
+
3
17
  ## 0.6.0
4
18
 
5
19
  ### Added
@@ -88,9 +88,7 @@ module Belt
88
88
  false
89
89
  end
90
90
 
91
- # before_action guard. Raises, because Belt discards before_action return values
92
- # (see BeltController::Base#run_before_actions) — returning a response hash would
93
- # let the action run anyway. Belt maps the error to 401.
91
+ # before_action guard. Raises NotAuthenticated, which Belt maps to 401.
94
92
  def authenticate_user!
95
93
  raise NotAuthenticated, 'Authentication required' unless user_signed_in?
96
94
  end
@@ -71,8 +71,8 @@ end
71
71
  ```
72
72
 
73
73
  `authenticate_user!` raises `Belt::Authentication::NotAuthenticated`, which Belt already
74
- maps to **401**. It has to raise: `before_action` cannot halt the chain by returning a
75
- response — return values are discarded and the action runs anyway.
74
+ maps to **401**. (Your own guards can also halt by calling a response helper, e.g.
75
+ `error_response('Forbidden', 403) unless admin?`.)
76
76
 
77
77
  | Method | |
78
78
  |---|---|
@@ -96,8 +96,19 @@ class ApplicationController < BeltController::Base
96
96
  end
97
97
  ```
98
98
 
99
- Callbacks run in definition order. `before_action` can halt the request by
100
- calling a response helper (e.g., `error_response`).
99
+ Callbacks run in definition order. A `before_action` halts the request by
100
+ calling a response helper (`error_response`, `success_response`, `head`,
101
+ `render`, …). The remaining callbacks, the action and the `after_action`s are
102
+ skipped, and that response is returned:
103
+
104
+ ```ruby
105
+ def require_admin!
106
+ error_response('Forbidden', 403) unless admin?
107
+ end
108
+ ```
109
+
110
+ Raising works too: the exception goes through `rescue_from` as usual (e.g.
111
+ `Belt::AuthenticationError` → 401).
101
112
 
102
113
  ## Strong Parameters
103
114
 
data/lib/belt/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Belt
4
- VERSION = '0.6.0'
4
+ VERSION = '0.6.1'
5
5
 
6
6
  # Ruby version new apps run on in Lambda. Rendered into the conveyor-belt
7
7
  # provider block (`ruby_version`) by `belt new` / `belt generate environment`.
@@ -9,12 +9,15 @@ require_relative '../belt/helpers/error_logging'
9
9
  require_relative '../belt/helpers/cors_origin'
10
10
  require_relative '../belt/rendering'
11
11
  require_relative 'implicit_response'
12
+ require_relative 'callback_halting'
12
13
 
13
14
  module BeltController
14
15
  class Base
15
16
  include Belt::Helpers::Response
16
17
  include Belt::Rendering
17
18
  include ImplicitResponse
19
+ # Must come after Belt::Helpers::Response / Belt::Rendering (wraps their helpers).
20
+ include CallbackHalting
18
21
  # Cognito identity: current_user, authenticate_user!, cognito_admin?.
19
22
  # Inert unless the app declares `cognito_authenticatable` on a model.
20
23
  include Belt::Authentication::Controller
@@ -139,7 +142,11 @@ module BeltController
139
142
  raise Belt::ActionNotFound, "The action '#{action_sym}' could not be found for #{self.class.name}"
140
143
  end
141
144
 
142
- run_before_actions(action_sym)
145
+ # A before_action that produced a response halts the request (Rails-style):
146
+ # the action and after_actions don't run.
147
+ halted = run_before_actions(action_sym)
148
+ return halted if halted
149
+
143
150
  # Snapshot ivars so we only auto-serialize assigns set by the action (Rails-style)
144
151
  @__assigns_before = instance_variables
145
152
  result = send(action_sym)
@@ -178,14 +185,17 @@ module BeltController
178
185
 
179
186
  private
180
187
 
188
+ # Returns the halting response if a callback produced one, else nil.
181
189
  def run_before_actions(action_sym)
182
190
  self.class.all_before_actions.each do |callback|
183
191
  next if callback[:only] && !callback[:only].include?(action_sym)
184
192
  next if callback[:except]&.include?(action_sym)
185
193
  next if should_skip_callback?(callback[:method], action_sym)
186
194
 
187
- send(callback[:method])
195
+ response = run_halting_callback(callback[:method])
196
+ return response if response
188
197
  end
198
+ nil
189
199
  end
190
200
 
191
201
  def run_after_actions(action_sym)
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BeltController
4
+ # Rails-style halting for before_action callbacks.
5
+ #
6
+ # A before_action halts the request by producing a response. Either form works:
7
+ #
8
+ # def require_admin!
9
+ # error_response('Forbidden', 403) unless admin?
10
+ # end
11
+ #
12
+ # def require_admin!
13
+ # return if admin?
14
+ #
15
+ # error_response('Forbidden', 403)
16
+ # Belt::Observability::Logger.warn('non-admin hit admin route')
17
+ # end
18
+ #
19
+ # Once a callback halts, the remaining callbacks, the action and the
20
+ # after_actions are skipped, and that response is returned.
21
+ #
22
+ # Belt's response helpers are pure (they build and return a hash), so we
23
+ # record any response built while a callback is running. That catches the
24
+ # second form, where the response isn't the callback's return value.
25
+ # Included by BeltController::Base after the response helpers so these
26
+ # wrappers sit in front of them in the ancestor chain.
27
+ module CallbackHalting
28
+ # render builds its response via html_response, so it's covered too.
29
+ %i[success_response error_response html_response head].each do |helper|
30
+ define_method(helper) do |*args|
31
+ response = super(*args)
32
+ @__callback_response = response if @__running_callback
33
+ response
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # Run one before_action. Returns the response it produced (halt), or nil.
40
+ # A returned response wins over one that was only built along the way.
41
+ def run_halting_callback(method_name)
42
+ @__callback_response = nil
43
+ @__running_callback = true
44
+ result = send(method_name)
45
+ lambda_response?(result) ? result : @__callback_response
46
+ ensure
47
+ @__running_callback = false
48
+ end
49
+ end
50
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: belt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stowzilla
@@ -192,6 +192,7 @@ files:
192
192
  - lib/belt/version.rb
193
193
  - lib/belt/views/welcome/show.html.erb
194
194
  - lib/belt_controller/base.rb
195
+ - lib/belt_controller/callback_halting.rb
195
196
  - lib/belt_controller/implicit_response.rb
196
197
  - lib/templates/dns/backend.tf.erb
197
198
  - lib/templates/dns/belt.rb.erb