hanami-controller 2.0.0.alpha8 → 2.0.0.beta1
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 +4 -4
- data/CHANGELOG.md +123 -3
- data/hanami-controller.gemspec +21 -20
- data/lib/hanami/action/base_params.rb +20 -57
- data/lib/hanami/action/cache/cache_control.rb +14 -10
- data/lib/hanami/action/cache/conditional_get.rb +8 -26
- data/lib/hanami/action/cache/directives.rb +8 -6
- data/lib/hanami/action/cache/expires.rb +10 -11
- data/lib/hanami/action/cache.rb +5 -3
- data/lib/hanami/action/configuration.rb +20 -12
- data/lib/hanami/action/constants.rb +261 -0
- data/lib/hanami/action/cookie_jar.rb +37 -55
- data/lib/hanami/action/cookies.rb +2 -0
- data/lib/hanami/action/csrf_protection.rb +28 -31
- data/lib/hanami/action/flash.rb +4 -0
- data/lib/hanami/action/halt.rb +4 -0
- data/lib/hanami/action/mime.rb +103 -73
- data/lib/hanami/action/params.rb +41 -31
- data/lib/hanami/action/rack/file.rb +5 -9
- data/lib/hanami/action/request.rb +10 -59
- data/lib/hanami/action/response.rb +89 -46
- data/lib/hanami/action/session.rb +5 -3
- data/lib/hanami/action/validatable.rb +18 -19
- data/lib/hanami/action/view_name_inferrer.rb +10 -0
- data/lib/hanami/action.rb +133 -216
- data/lib/hanami/controller/error.rb +2 -0
- data/lib/hanami/controller/version.rb +3 -1
- data/lib/hanami/controller.rb +10 -12
- data/lib/hanami/http/status.rb +3 -1
- metadata +22 -8
- data/lib/hanami/action/glue.rb +0 -40
data/lib/hanami/action/params.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/action/base_params"
|
4
|
+
require "hanami/validations/form"
|
3
5
|
|
4
6
|
module Hanami
|
5
7
|
class Action
|
@@ -48,45 +50,41 @@ module Hanami
|
|
48
50
|
# @example Basic usage
|
49
51
|
# require "hanami/controller"
|
50
52
|
#
|
51
|
-
# class MyAction
|
52
|
-
# include Hanami::Action
|
53
|
-
#
|
53
|
+
# class MyAction < Hanami::Action
|
54
54
|
# params do
|
55
55
|
# required(:book).schema do
|
56
56
|
# required(:isbn).filled(:str?)
|
57
57
|
# end
|
58
58
|
# end
|
59
59
|
#
|
60
|
-
# def
|
60
|
+
# def handle(req, res)
|
61
61
|
# # 1. Don't try to save the record if the params aren't valid
|
62
|
-
# return unless params.valid?
|
62
|
+
# return unless req.params.valid?
|
63
63
|
#
|
64
|
-
# BookRepository.new.create(params[:book])
|
64
|
+
# BookRepository.new.create(req.params[:book])
|
65
65
|
# rescue Hanami::Model::UniqueConstraintViolationError
|
66
66
|
# # 2. Add an error in case the record wasn't unique
|
67
|
-
# params.errors.add(:book, :isbn, "is not unique")
|
67
|
+
# req.params.errors.add(:book, :isbn, "is not unique")
|
68
68
|
# end
|
69
69
|
# end
|
70
70
|
#
|
71
71
|
# @example Invalid argument
|
72
72
|
# require "hanami/controller"
|
73
73
|
#
|
74
|
-
# class MyAction
|
75
|
-
# include Hanami::Action
|
76
|
-
#
|
74
|
+
# class MyAction < Hanami::Action
|
77
75
|
# params do
|
78
76
|
# required(:book).schema do
|
79
77
|
# required(:title).filled(:str?)
|
80
78
|
# end
|
81
79
|
# end
|
82
80
|
#
|
83
|
-
# def
|
84
|
-
# puts params.to_h # => {}
|
85
|
-
# puts params.valid? # => false
|
86
|
-
# puts params.error_messages # => ["Book is missing"]
|
87
|
-
# puts params.errors # => {:book=>["is missing"]}
|
81
|
+
# def handle(req, *)
|
82
|
+
# puts req.params.to_h # => {}
|
83
|
+
# puts req.params.valid? # => false
|
84
|
+
# puts req.params.error_messages # => ["Book is missing"]
|
85
|
+
# puts req.params.errors # => {:book=>["is missing"]}
|
88
86
|
#
|
89
|
-
# params.errors.add(:book, :isbn, "is not unique") # => ArgumentError
|
87
|
+
# req.params.errors.add(:book, :isbn, "is not unique") # => ArgumentError
|
90
88
|
# end
|
91
89
|
# end
|
92
90
|
def add(*args)
|
@@ -129,9 +127,8 @@ module Hanami
|
|
129
127
|
# @see https://guides.hanamirb.org/validations/overview
|
130
128
|
#
|
131
129
|
# @example
|
132
|
-
# class Signup
|
130
|
+
# class Signup < Hanami::Action
|
133
131
|
# MEGABYTE = 1024 ** 2
|
134
|
-
# include Hanami::Action
|
135
132
|
#
|
136
133
|
# params do
|
137
134
|
# required(:first_name).filled(:str?)
|
@@ -143,13 +140,13 @@ module Hanami
|
|
143
140
|
# optional(:avatar).filled(size?: 1..(MEGABYTE * 3))
|
144
141
|
# end
|
145
142
|
#
|
146
|
-
# def
|
147
|
-
# halt 400 unless params.valid?
|
143
|
+
# def handle(req, *)
|
144
|
+
# halt 400 unless req.params.valid?
|
148
145
|
# # ...
|
149
146
|
# end
|
150
147
|
# end
|
151
148
|
def self.params(&blk)
|
152
|
-
validations(&blk || ->
|
149
|
+
validations(&blk || -> {})
|
153
150
|
end
|
154
151
|
|
155
152
|
# Initialize the params and freeze them.
|
@@ -186,7 +183,13 @@ module Hanami
|
|
186
183
|
#
|
187
184
|
# @example
|
188
185
|
# params.errors
|
189
|
-
# # => {
|
186
|
+
# # => {
|
187
|
+
# :email=>["is missing", "is in invalid format"],
|
188
|
+
# :name=>["is missing"],
|
189
|
+
# :tos=>["is missing"],
|
190
|
+
# :age=>["is missing"],
|
191
|
+
# :address=>["is missing"]
|
192
|
+
# }
|
190
193
|
attr_reader :errors
|
191
194
|
|
192
195
|
# Returns flat collection of full error messages
|
@@ -197,18 +200,25 @@ module Hanami
|
|
197
200
|
#
|
198
201
|
# @example
|
199
202
|
# params.error_messages
|
200
|
-
# # => [
|
203
|
+
# # => [
|
204
|
+
# "Email is missing",
|
205
|
+
# "Email is in invalid format",
|
206
|
+
# "Name is missing",
|
207
|
+
# "Tos is missing",
|
208
|
+
# "Age is missing",
|
209
|
+
# "Address is missing"
|
210
|
+
# ]
|
201
211
|
def error_messages(error_set = errors)
|
202
212
|
error_set.each_with_object([]) do |(key, messages), result|
|
203
213
|
k = Utils::String.titleize(key)
|
204
214
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
215
|
+
msgs = if messages.is_a?(::Hash)
|
216
|
+
error_messages(messages)
|
217
|
+
else
|
218
|
+
messages.map { |message| "#{k} #{message}" }
|
219
|
+
end
|
210
220
|
|
211
|
-
result.concat(
|
221
|
+
result.concat(msgs)
|
212
222
|
end
|
213
223
|
end
|
214
224
|
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack/file"
|
2
4
|
|
3
5
|
module Hanami
|
4
6
|
class Action
|
@@ -10,12 +12,6 @@ module Hanami
|
|
10
12
|
#
|
11
13
|
# @see Hanami::Action::Rack#send_file
|
12
14
|
class File
|
13
|
-
# The key that returns path info from the Rack env
|
14
|
-
#
|
15
|
-
# @since 1.0.0
|
16
|
-
# @api private
|
17
|
-
PATH_INFO = "PATH_INFO".freeze
|
18
|
-
|
19
15
|
# @param path [String,Pathname] file path
|
20
16
|
#
|
21
17
|
# @since 0.4.3
|
@@ -29,11 +25,11 @@ module Hanami
|
|
29
25
|
# @api private
|
30
26
|
def call(env)
|
31
27
|
env = env.dup
|
32
|
-
env[PATH_INFO] = @path
|
28
|
+
env[Action::PATH_INFO] = @path
|
33
29
|
|
34
30
|
@file.get(env)
|
35
31
|
rescue Errno::ENOENT
|
36
|
-
[
|
32
|
+
[Action::NOT_FOUND, {}, nil]
|
37
33
|
end
|
38
34
|
end
|
39
35
|
end
|
@@ -1,5 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack/utils"
|
4
|
+
require "rack/mime"
|
5
|
+
require "rack/request"
|
6
|
+
require "securerandom"
|
3
7
|
|
4
8
|
module Hanami
|
5
9
|
class Action
|
@@ -10,11 +14,6 @@ module Hanami
|
|
10
14
|
#
|
11
15
|
# @see http://www.rubydoc.info/gems/rack/Rack/Request
|
12
16
|
class Request < ::Rack::Request
|
13
|
-
HTTP_ACCEPT = "HTTP_ACCEPT".freeze
|
14
|
-
REQUEST_ID = "hanami.request_id".freeze
|
15
|
-
DEFAULT_ACCEPT = "*/*".freeze
|
16
|
-
DEFAULT_ID_LENGTH = 16
|
17
|
-
|
18
17
|
attr_reader :params
|
19
18
|
|
20
19
|
def initialize(env, params)
|
@@ -23,8 +22,8 @@ module Hanami
|
|
23
22
|
end
|
24
23
|
|
25
24
|
def id
|
26
|
-
# FIXME make this number configurable and document the probabilities of clashes
|
27
|
-
@id ||= @env[REQUEST_ID] = SecureRandom.hex(DEFAULT_ID_LENGTH)
|
25
|
+
# FIXME: make this number configurable and document the probabilities of clashes
|
26
|
+
@id ||= @env[Action::REQUEST_ID] = SecureRandom.hex(Action::DEFAULT_ID_LENGTH)
|
28
27
|
end
|
29
28
|
|
30
29
|
def accept?(mime_type)
|
@@ -34,61 +33,13 @@ module Hanami
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def accept_header?
|
37
|
-
accept != DEFAULT_ACCEPT
|
36
|
+
accept != Action::DEFAULT_ACCEPT
|
38
37
|
end
|
39
38
|
|
40
39
|
# @since 0.1.0
|
41
40
|
# @api private
|
42
41
|
def accept
|
43
|
-
@accept ||= @env[HTTP_ACCEPT] || DEFAULT_ACCEPT
|
44
|
-
end
|
45
|
-
|
46
|
-
# @raise [NotImplementedError]
|
47
|
-
#
|
48
|
-
# @since 0.3.1
|
49
|
-
# @api private
|
50
|
-
def content_type
|
51
|
-
raise NotImplementedError, 'Please use Action#content_type'
|
52
|
-
end
|
53
|
-
|
54
|
-
# @raise [NotImplementedError]
|
55
|
-
#
|
56
|
-
# @since 0.3.1
|
57
|
-
# @api private
|
58
|
-
def update_param(*)
|
59
|
-
raise NotImplementedError, 'Please use params passed to Action#call'
|
60
|
-
end
|
61
|
-
|
62
|
-
# @raise [NotImplementedError]
|
63
|
-
#
|
64
|
-
# @since 0.3.1
|
65
|
-
# @api private
|
66
|
-
def delete_param(*)
|
67
|
-
raise NotImplementedError, 'Please use params passed to Action#call'
|
68
|
-
end
|
69
|
-
|
70
|
-
# @raise [NotImplementedError]
|
71
|
-
#
|
72
|
-
# @since 0.3.1
|
73
|
-
# @api private
|
74
|
-
def [](*)
|
75
|
-
raise NotImplementedError, 'Please use params passed to Action#call'
|
76
|
-
end
|
77
|
-
|
78
|
-
# @raise [NotImplementedError]
|
79
|
-
#
|
80
|
-
# @since 0.3.1
|
81
|
-
# @api private
|
82
|
-
def []=(*)
|
83
|
-
raise NotImplementedError, 'Please use params passed to Action#call'
|
84
|
-
end
|
85
|
-
|
86
|
-
# @raise [NotImplementedError]
|
87
|
-
#
|
88
|
-
# @since 0.3.1
|
89
|
-
# @api private
|
90
|
-
def values_at(*)
|
91
|
-
raise NotImplementedError, 'Please use params passed to Action#call'
|
42
|
+
@accept ||= @env[Action::HTTP_ACCEPT] || Action::DEFAULT_ACCEPT
|
92
43
|
end
|
93
44
|
end
|
94
45
|
end
|
@@ -1,61 +1,58 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
3
|
+
require "rack"
|
4
|
+
require "rack/response"
|
5
|
+
require "hanami/utils/kernel"
|
6
|
+
require "hanami/action/flash"
|
7
|
+
require "hanami/action/halt"
|
8
|
+
require "hanami/action/cookie_jar"
|
9
|
+
require "hanami/action/cache/cache_control"
|
10
|
+
require "hanami/action/cache/expires"
|
11
|
+
require "hanami/action/cache/conditional_get"
|
12
12
|
|
13
13
|
module Hanami
|
14
14
|
class Action
|
15
15
|
class Response < ::Rack::Response
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
HTTP_ACCEPT = "HTTP_ACCEPT"
|
20
|
-
SESSION_KEY = "rack.session"
|
21
|
-
REQUEST_ID = "hanami.request_id"
|
22
|
-
LOCATION = "Location"
|
23
|
-
|
24
|
-
X_CASCADE = "X-Cascade"
|
25
|
-
CONTENT_LENGTH = "Content-Length"
|
26
|
-
NOT_FOUND = 404
|
27
|
-
|
28
|
-
RACK_STATUS = 0
|
29
|
-
RACK_HEADERS = 1
|
30
|
-
RACK_BODY = 2
|
31
|
-
|
32
|
-
HEAD = "HEAD"
|
33
|
-
|
34
|
-
FLASH_SESSION_KEY = "_flash"
|
16
|
+
# @since 2.0.0
|
17
|
+
# @api private
|
18
|
+
DEFAULT_VIEW_OPTIONS = -> (*) { {} }.freeze
|
35
19
|
|
20
|
+
# @since 2.0.0
|
21
|
+
# @api private
|
36
22
|
EMPTY_BODY = [].freeze
|
37
23
|
|
24
|
+
# @since 2.0.0
|
25
|
+
# @api private
|
38
26
|
FILE_SYSTEM_ROOT = Pathname.new("/").freeze
|
39
27
|
|
28
|
+
# @since 2.0.0
|
29
|
+
# @api private
|
40
30
|
attr_reader :request, :action, :exposures, :format, :env, :view_options
|
31
|
+
|
32
|
+
# @since 2.0.0
|
33
|
+
# @api private
|
41
34
|
attr_accessor :charset
|
42
35
|
|
36
|
+
# @since 2.0.0
|
37
|
+
# @api private
|
43
38
|
def self.build(status, env)
|
44
|
-
new(action: "", configuration: nil, content_type: Mime.best_q_match(env[HTTP_ACCEPT]), env: env).tap do |r|
|
39
|
+
new(action: "", configuration: nil, content_type: Mime.best_q_match(env[Action::HTTP_ACCEPT]), env: env).tap do |r| # rubocop:disable Layout/LineLength
|
45
40
|
r.status = status
|
46
41
|
r.body = Http::Status.message_for(status)
|
47
42
|
r.set_format(Mime.format_for(r.content_type))
|
48
43
|
end
|
49
44
|
end
|
50
45
|
|
51
|
-
|
46
|
+
# @since 2.0.0
|
47
|
+
# @api private
|
48
|
+
def initialize(request:, action:, configuration:, content_type: nil, env: {}, headers: {}, view_options: nil) # rubocop:disable Metrics/ParameterLists
|
52
49
|
super([], 200, headers.dup)
|
53
|
-
set_header(
|
50
|
+
set_header(Action::CONTENT_TYPE, content_type)
|
54
51
|
|
55
52
|
@request = request
|
56
53
|
@action = action
|
57
54
|
@configuration = configuration
|
58
|
-
@charset = ::Rack::MediaType.params(content_type).fetch(
|
55
|
+
@charset = ::Rack::MediaType.params(content_type).fetch("charset", nil)
|
59
56
|
@exposures = {}
|
60
57
|
@env = env
|
61
58
|
@view_options = view_options || DEFAULT_VIEW_OPTIONS
|
@@ -63,6 +60,8 @@ module Hanami
|
|
63
60
|
@sending_file = false
|
64
61
|
end
|
65
62
|
|
63
|
+
# @since 2.0.0
|
64
|
+
# @api public
|
66
65
|
def body=(str)
|
67
66
|
@length = 0
|
68
67
|
@body = EMPTY_BODY.dup
|
@@ -75,49 +74,69 @@ module Hanami
|
|
75
74
|
end
|
76
75
|
end
|
77
76
|
|
77
|
+
# @since 2.0.0
|
78
|
+
# @api public
|
78
79
|
def render(view, **options)
|
79
80
|
self.body = view.(**view_options.(request, self), **exposures.merge(options)).to_str
|
80
81
|
end
|
81
82
|
|
83
|
+
# @since 2.0.0
|
84
|
+
# @api public
|
82
85
|
def format=(args)
|
83
86
|
@format, content_type = *args
|
84
87
|
content_type = Action::Mime.content_type_with_charset(content_type, charset)
|
85
88
|
set_header("Content-Type", content_type)
|
86
89
|
end
|
87
90
|
|
91
|
+
# @since 2.0.0
|
92
|
+
# @api public
|
88
93
|
def [](key)
|
89
94
|
@exposures.fetch(key)
|
90
95
|
end
|
91
96
|
|
97
|
+
# @since 2.0.0
|
98
|
+
# @api public
|
92
99
|
def []=(key, value)
|
93
100
|
@exposures[key] = value
|
94
101
|
end
|
95
102
|
|
103
|
+
# @since 2.0.0
|
104
|
+
# @api public
|
96
105
|
def session
|
97
|
-
env[
|
106
|
+
env[Action::RACK_SESSION] ||= {}
|
98
107
|
end
|
99
108
|
|
109
|
+
# @since 2.0.0
|
110
|
+
# @api public
|
100
111
|
def cookies
|
101
112
|
@cookies ||= CookieJar.new(env.dup, headers, @configuration.cookies)
|
102
113
|
end
|
103
114
|
|
115
|
+
# @since 2.0.0
|
116
|
+
# @api public
|
104
117
|
def flash
|
105
|
-
@flash ||= Flash.new(session[
|
118
|
+
@flash ||= Flash.new(session[Flash::KEY])
|
106
119
|
end
|
107
120
|
|
121
|
+
# @since 2.0.0
|
122
|
+
# @api public
|
108
123
|
def redirect_to(url, status: 302)
|
109
|
-
return unless
|
124
|
+
return unless allow_redirect?
|
110
125
|
|
111
126
|
redirect(::String.new(url), status)
|
112
127
|
Halt.call(status)
|
113
128
|
end
|
114
129
|
|
130
|
+
# @since 2.0.0
|
131
|
+
# @api public
|
115
132
|
def send_file(path)
|
116
133
|
_send_file(
|
117
134
|
Rack::File.new(path, @configuration.public_directory).call(env)
|
118
135
|
)
|
119
136
|
end
|
120
137
|
|
138
|
+
# @since 2.0.0
|
139
|
+
# @api public
|
121
140
|
def unsafe_send_file(path)
|
122
141
|
directory = if Pathname.new(path).relative?
|
123
142
|
@configuration.root_directory
|
@@ -130,16 +149,22 @@ module Hanami
|
|
130
149
|
)
|
131
150
|
end
|
132
151
|
|
152
|
+
# @since 2.0.0
|
153
|
+
# @api public
|
133
154
|
def cache_control(*values)
|
134
155
|
directives = Cache::CacheControl::Directives.new(*values)
|
135
156
|
headers.merge!(directives.headers)
|
136
157
|
end
|
137
158
|
|
159
|
+
# @since 2.0.0
|
160
|
+
# @api public
|
138
161
|
def expires(amount, *values)
|
139
162
|
directives = Cache::Expires::Directives.new(amount, *values)
|
140
163
|
headers.merge!(directives.headers)
|
141
164
|
end
|
142
165
|
|
166
|
+
# @since 2.0.0
|
167
|
+
# @api public
|
143
168
|
def fresh(options)
|
144
169
|
conditional_get = Cache::ConditionalGet.new(env, options)
|
145
170
|
|
@@ -150,41 +175,59 @@ module Hanami
|
|
150
175
|
end
|
151
176
|
end
|
152
177
|
|
178
|
+
# @since 2.0.0
|
153
179
|
# @api private
|
154
180
|
def request_id
|
155
|
-
env.fetch(REQUEST_ID) do
|
181
|
+
env.fetch(Action::REQUEST_ID) do
|
156
182
|
# FIXME: raise a meaningful error, by inviting devs to include Hanami::Action::Session
|
157
183
|
raise "Can't find request ID"
|
158
184
|
end
|
159
185
|
end
|
160
186
|
|
161
|
-
|
187
|
+
# @since 2.0.0
|
188
|
+
# @api public
|
189
|
+
def set_format(value) # rubocop:disable Naming/AccessorMethodName
|
162
190
|
@format = value
|
163
191
|
end
|
164
192
|
|
193
|
+
# @since 2.0.0
|
194
|
+
# @api private
|
165
195
|
def renderable?
|
166
196
|
return !head? && body.empty? if body.respond_to?(:empty?)
|
167
197
|
|
168
198
|
!@sending_file && !head?
|
169
199
|
end
|
170
200
|
|
171
|
-
|
201
|
+
# @since 2.0.0
|
202
|
+
# @api private
|
203
|
+
def allow_redirect?
|
204
|
+
return body.empty? if body.respond_to?(:empty?)
|
205
|
+
|
206
|
+
!@sending_file
|
207
|
+
end
|
208
|
+
|
209
|
+
# @since 2.0.0
|
210
|
+
# @api private
|
211
|
+
alias_method :to_ary, :to_a
|
172
212
|
|
213
|
+
# @since 2.0.0
|
214
|
+
# @api public
|
173
215
|
def head?
|
174
|
-
env[REQUEST_METHOD] == HEAD
|
216
|
+
env[Action::REQUEST_METHOD] == Action::HEAD
|
175
217
|
end
|
176
218
|
|
219
|
+
# @since 2.0.0
|
177
220
|
# @api private
|
178
221
|
def _send_file(send_file_response)
|
179
|
-
headers.merge!(send_file_response[
|
222
|
+
headers.merge!(send_file_response[Action::RESPONSE_HEADERS])
|
180
223
|
|
181
|
-
if send_file_response[
|
182
|
-
headers.delete(X_CASCADE)
|
183
|
-
headers.delete(CONTENT_LENGTH)
|
184
|
-
Halt.call(NOT_FOUND)
|
224
|
+
if send_file_response[Action::RESPONSE_CODE] == Action::NOT_FOUND
|
225
|
+
headers.delete(Action::X_CASCADE)
|
226
|
+
headers.delete(Action::CONTENT_LENGTH)
|
227
|
+
Halt.call(Action::NOT_FOUND)
|
185
228
|
else
|
186
|
-
self.status = send_file_response[
|
187
|
-
self.body = send_file_response[
|
229
|
+
self.status = send_file_response[Action::RESPONSE_CODE]
|
230
|
+
self.body = send_file_response[Action::RESPONSE_BODY]
|
188
231
|
@sending_file = true
|
189
232
|
end
|
190
233
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/action/flash"
|
2
4
|
|
3
5
|
module Hanami
|
4
6
|
class Action
|
@@ -26,9 +28,9 @@ module Hanami
|
|
26
28
|
# @see Hanami::Action#finish
|
27
29
|
def finish(req, res, *)
|
28
30
|
if (next_flash = res.flash.next).any?
|
29
|
-
res.session[
|
31
|
+
res.session[Flash::KEY] = next_flash
|
30
32
|
else
|
31
|
-
res.session.delete(
|
33
|
+
res.session.delete(Flash::KEY)
|
32
34
|
end
|
33
35
|
|
34
36
|
super
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/action/params"
|
2
4
|
|
3
5
|
module Hanami
|
4
6
|
class Action
|
@@ -7,7 +9,7 @@ module Hanami
|
|
7
9
|
#
|
8
10
|
# @api private
|
9
11
|
# @since 0.3.0
|
10
|
-
PARAMS_CLASS_NAME =
|
12
|
+
PARAMS_CLASS_NAME = "Params"
|
11
13
|
|
12
14
|
# @api private
|
13
15
|
# @since 0.1.0
|
@@ -53,28 +55,26 @@ module Hanami
|
|
53
55
|
# @see https://guides.hanamirb.org//validations/overview
|
54
56
|
#
|
55
57
|
# @example Anonymous Block
|
56
|
-
# require
|
57
|
-
#
|
58
|
-
# class Signup
|
59
|
-
# include Hanami::Action
|
58
|
+
# require "hanami/controller"
|
60
59
|
#
|
60
|
+
# class Signup < Hanami::Action
|
61
61
|
# params do
|
62
62
|
# required(:first_name)
|
63
63
|
# required(:last_name)
|
64
64
|
# required(:email)
|
65
65
|
# end
|
66
66
|
#
|
67
|
-
# def
|
68
|
-
# puts params.class # => Signup::Params
|
69
|
-
# puts params.class.superclass # => Hanami::Action::Params
|
67
|
+
# def handle(req, *)
|
68
|
+
# puts req.params.class # => Signup::Params
|
69
|
+
# puts req.params.class.superclass # => Hanami::Action::Params
|
70
70
|
#
|
71
|
-
# puts params[:first_name] # => "Luca"
|
72
|
-
# puts params[:admin] # => nil
|
71
|
+
# puts req.params[:first_name] # => "Luca"
|
72
|
+
# puts req.params[:admin] # => nil
|
73
73
|
# end
|
74
74
|
# end
|
75
75
|
#
|
76
76
|
# @example Concrete class
|
77
|
-
# require
|
77
|
+
# require "hanami/controller"
|
78
78
|
#
|
79
79
|
# class SignupParams < Hanami::Action::Params
|
80
80
|
# required(:first_name)
|
@@ -82,16 +82,15 @@ module Hanami
|
|
82
82
|
# required(:email)
|
83
83
|
# end
|
84
84
|
#
|
85
|
-
# class Signup
|
86
|
-
# include Hanami::Action
|
85
|
+
# class Signup < Hanami::Action
|
87
86
|
# params SignupParams
|
88
87
|
#
|
89
|
-
# def
|
90
|
-
# puts params.class # => SignupParams
|
91
|
-
# puts params.class.superclass # => Hanami::Action::Params
|
88
|
+
# def handle(req, *)
|
89
|
+
# puts req.params.class # => SignupParams
|
90
|
+
# puts req.params.class.superclass # => Hanami::Action::Params
|
92
91
|
#
|
93
|
-
# params[:first_name] # => "Luca"
|
94
|
-
# params[:admin] # => nil
|
92
|
+
# req.params[:first_name] # => "Luca"
|
93
|
+
# req.params[:admin] # => nil
|
95
94
|
# end
|
96
95
|
# end
|
97
96
|
def params(klass = nil, &blk)
|
@@ -2,13 +2,19 @@
|
|
2
2
|
|
3
3
|
module Hanami
|
4
4
|
class Action
|
5
|
+
# @since 2.0.0
|
6
|
+
# @api private
|
5
7
|
class ViewNameInferrer
|
8
|
+
# @since 2.0.0
|
9
|
+
# @api private
|
6
10
|
ALTERNATIVE_NAMES = {
|
7
11
|
"create" => "new",
|
8
12
|
"update" => "edit"
|
9
13
|
}.freeze
|
10
14
|
|
11
15
|
class << self
|
16
|
+
# @since 2.0.0
|
17
|
+
# @api private
|
12
18
|
def call(action_name:, provider:)
|
13
19
|
application = provider.respond_to?(:application) ? provider.application : Hanami.application
|
14
20
|
|
@@ -24,6 +30,8 @@ module Hanami
|
|
24
30
|
|
25
31
|
private
|
26
32
|
|
33
|
+
# @since 2.0.0
|
34
|
+
# @api private
|
27
35
|
def action_identifier_name(action_name, provider, name_base)
|
28
36
|
provider
|
29
37
|
.inflector
|
@@ -33,6 +41,8 @@ module Hanami
|
|
33
41
|
.gsub("/", ".")
|
34
42
|
end
|
35
43
|
|
44
|
+
# @since 2.0.0
|
45
|
+
# @api private
|
36
46
|
def alternative_view_name(view_name)
|
37
47
|
parts = view_name.split(".")
|
38
48
|
|