hanami-controller 2.0.0.alpha8 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|