superform 0.5.1 → 0.6.0
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 +131 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +128 -27
- data/README.md +183 -54
- data/SPEC_STYLE_GUIDE.md +146 -0
- data/lib/generators/superform/install/USAGE +6 -2
- data/lib/generators/superform/install/install_generator.rb +11 -22
- data/lib/generators/superform/install/templates/base.rb +33 -0
- data/lib/superform/field.rb +82 -0
- data/lib/superform/form.rb +34 -0
- data/lib/superform/namespace.rb +25 -15
- data/lib/superform/namespace_collection.rb +7 -4
- data/lib/superform/rails/components/base.rb +31 -0
- data/lib/superform/rails/components/button.rb +20 -0
- data/lib/superform/rails/components/checkbox.rb +19 -0
- data/lib/superform/rails/components/field.rb +11 -0
- data/lib/superform/rails/components/input.rb +59 -0
- data/lib/superform/rails/components/label.rb +20 -0
- data/lib/superform/rails/components/select.rb +43 -0
- data/lib/superform/rails/components/textarea.rb +12 -0
- data/lib/superform/rails/form.rb +240 -0
- data/lib/superform/rails/option_mapper.rb +36 -0
- data/lib/superform/rails/strong_parameters.rb +73 -0
- data/lib/superform/rails.rb +17 -368
- data/lib/superform/version.rb +1 -1
- metadata +21 -14
- data/lib/generators/superform/install/templates/application_form.rb +0 -31
@@ -0,0 +1,36 @@
|
|
1
|
+
module Superform
|
2
|
+
module Rails
|
3
|
+
# Accept a collection of objects and map them to options suitable for form controls, like `select > options`
|
4
|
+
class OptionMapper
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(collection)
|
8
|
+
@collection = collection
|
9
|
+
end
|
10
|
+
|
11
|
+
def each(&options)
|
12
|
+
@collection.each do |object|
|
13
|
+
case object
|
14
|
+
in ActiveRecord::Relation => relation
|
15
|
+
active_record_relation_options_enumerable(relation).each(&options)
|
16
|
+
in id, value
|
17
|
+
options.call id, value
|
18
|
+
in value
|
19
|
+
options.call value, value.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def active_record_relation_options_enumerable(relation)
|
25
|
+
Enumerator.new do |collection|
|
26
|
+
relation.each do |object|
|
27
|
+
attributes = object.attributes
|
28
|
+
id = attributes.delete(relation.primary_key)
|
29
|
+
value = attributes.values.join(" ")
|
30
|
+
collection << [ id, value ]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Superform
|
2
|
+
module Rails
|
3
|
+
module StrongParameters
|
4
|
+
protected
|
5
|
+
# Assigns permitted params to the given form and returns the model.
|
6
|
+
# Usage in a controller when you want to build/validate without saving:
|
7
|
+
#
|
8
|
+
# def preview
|
9
|
+
# @post = Post.new
|
10
|
+
# post = permit PostForm.new(@post)
|
11
|
+
# # post now has attributes from params, but is not persisted
|
12
|
+
# render :preview
|
13
|
+
# end
|
14
|
+
def permit(form)
|
15
|
+
form_params = params.require(form.key)
|
16
|
+
assign(form_params, to: form).model
|
17
|
+
end
|
18
|
+
|
19
|
+
# Saves the form's underlying model after assigning permitted params.
|
20
|
+
# Typical Rails controller usage (create):
|
21
|
+
#
|
22
|
+
# def create
|
23
|
+
# @post = Post.new
|
24
|
+
# if save PostForm.new(@post)
|
25
|
+
# redirect_to @post
|
26
|
+
# else
|
27
|
+
# render :new, status: :unprocessable_entity
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# Typical Rails controller usage (update):
|
32
|
+
#
|
33
|
+
# def update
|
34
|
+
# @post = Post.find(params[:id])
|
35
|
+
# if save PostForm.new(@post)
|
36
|
+
# redirect_to @post
|
37
|
+
# else
|
38
|
+
# render :edit, status: :unprocessable_entity
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
def save(form)
|
42
|
+
permit(form).save
|
43
|
+
end
|
44
|
+
|
45
|
+
# Bang version that raises on validation failure.
|
46
|
+
# Useful when you prefer exceptions or are in a transaction:
|
47
|
+
#
|
48
|
+
# def create
|
49
|
+
# @post = Post.new
|
50
|
+
# save! PostForm.new(@post)
|
51
|
+
# redirect_to @post
|
52
|
+
# rescue ActiveRecord::RecordInvalid
|
53
|
+
# render :new, status: :unprocessable_entity
|
54
|
+
# end
|
55
|
+
def save!(form)
|
56
|
+
permit(form).save!
|
57
|
+
end
|
58
|
+
|
59
|
+
# Assigns params to the form and returns the form.
|
60
|
+
def assign(params, to:)
|
61
|
+
to.tap do |form|
|
62
|
+
# This output of this string goes nowhere since it likely
|
63
|
+
# won't be used. I'm not sure if I'm right about this though,
|
64
|
+
# If I'm wrong, then I think I need to encapsulate this module
|
65
|
+
# into a class that can store the rendered HTML that can be
|
66
|
+
# rendered later.
|
67
|
+
render_to_string form
|
68
|
+
form.assign params
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/superform/rails.rb
CHANGED
@@ -1,373 +1,22 @@
|
|
1
|
+
require "phlex/rails"
|
2
|
+
|
1
3
|
module Superform
|
2
4
|
module Rails
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
# method and the HTTP verb via the `_method_field`.
|
16
|
-
class Form < Component
|
17
|
-
attr_accessor :model
|
18
|
-
|
19
|
-
delegate \
|
20
|
-
:field,
|
21
|
-
:collection,
|
22
|
-
:namespace,
|
23
|
-
:assign,
|
24
|
-
:serialize,
|
25
|
-
to: :@namespace
|
26
|
-
|
27
|
-
# The Field class is designed to be extended to create custom forms. To override,
|
28
|
-
# in your subclass you may have something like this:
|
29
|
-
#
|
30
|
-
# ```ruby
|
31
|
-
# class MyForm < Superform::Rails::Form
|
32
|
-
# class MyLabel < Superform::Rails::Components::LabelComponent
|
33
|
-
# def view_template(&content)
|
34
|
-
# label(form: @field.dom.name, class: "text-bold", &content)
|
35
|
-
# end
|
36
|
-
# end
|
37
|
-
#
|
38
|
-
# class Field < Field
|
39
|
-
# def label(**attributes)
|
40
|
-
# MyLabel.new(self, **attributes)
|
41
|
-
# end
|
42
|
-
# end
|
43
|
-
# end
|
44
|
-
# ```
|
45
|
-
#
|
46
|
-
# Now all calls to `label` will have the `text-bold` class applied to it.
|
47
|
-
class Field < Superform::Field
|
48
|
-
def button(**attributes)
|
49
|
-
Components::ButtonComponent.new(self, attributes: attributes)
|
50
|
-
end
|
51
|
-
|
52
|
-
def input(**attributes)
|
53
|
-
Components::InputComponent.new(self, attributes: attributes)
|
54
|
-
end
|
55
|
-
|
56
|
-
def checkbox(**attributes)
|
57
|
-
Components::CheckboxComponent.new(self, attributes: attributes)
|
58
|
-
end
|
59
|
-
|
60
|
-
def label(**attributes, &)
|
61
|
-
Components::LabelComponent.new(self, attributes: attributes, &)
|
62
|
-
end
|
63
|
-
|
64
|
-
def textarea(**attributes)
|
65
|
-
Components::TextareaComponent.new(self, attributes: attributes)
|
66
|
-
end
|
67
|
-
|
68
|
-
def select(*collection, **attributes, &)
|
69
|
-
Components::SelectField.new(self, attributes: attributes, collection: collection, &)
|
70
|
-
end
|
71
|
-
|
72
|
-
def title
|
73
|
-
key.to_s.titleize
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def initialize(model, action: nil, method: nil, **attributes)
|
78
|
-
@model = model
|
79
|
-
@action = action
|
80
|
-
@method = method
|
81
|
-
@attributes = attributes
|
82
|
-
@namespace = Namespace.root(key, object: model, field_class: self.class::Field)
|
83
|
-
end
|
84
|
-
|
85
|
-
def around_template(&)
|
86
|
-
form_tag do
|
87
|
-
authenticity_token_field
|
88
|
-
_method_field
|
89
|
-
super
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def form_tag(&)
|
94
|
-
form action: form_action, method: form_method, **@attributes, &
|
95
|
-
end
|
96
|
-
|
97
|
-
def view_template(&block)
|
98
|
-
yield_content(&block)
|
99
|
-
end
|
100
|
-
|
101
|
-
def submit(value = submit_value, **attributes)
|
102
|
-
input **attributes.merge(
|
103
|
-
name: "commit",
|
104
|
-
type: "submit",
|
105
|
-
value: value
|
106
|
-
)
|
107
|
-
end
|
108
|
-
|
109
|
-
def key
|
110
|
-
@model.model_name.param_key
|
111
|
-
end
|
112
|
-
|
113
|
-
protected
|
114
|
-
def authenticity_token_field
|
115
|
-
input(
|
116
|
-
name: "authenticity_token",
|
117
|
-
type: "hidden",
|
118
|
-
value: helpers.form_authenticity_token
|
119
|
-
)
|
120
|
-
end
|
121
|
-
|
122
|
-
def _method_field
|
123
|
-
input(
|
124
|
-
name: "_method",
|
125
|
-
type: "hidden",
|
126
|
-
value: _method_field_value
|
127
|
-
)
|
128
|
-
end
|
129
|
-
|
130
|
-
def _method_field_value
|
131
|
-
@method || resource_method_field_value
|
132
|
-
end
|
133
|
-
|
134
|
-
def resource_method_field_value
|
135
|
-
@model.persisted? ? "patch" : "post"
|
136
|
-
end
|
137
|
-
|
138
|
-
def submit_value
|
139
|
-
"#{resource_action.to_s.capitalize} #{@model.model_name}"
|
140
|
-
end
|
141
|
-
|
142
|
-
def resource_action
|
143
|
-
@model.persisted? ? :update : :create
|
144
|
-
end
|
145
|
-
|
146
|
-
def form_action
|
147
|
-
@action ||= helpers.url_for(action: resource_action)
|
148
|
-
end
|
149
|
-
|
150
|
-
def form_method
|
151
|
-
@method.to_s.downcase == "get" ? "get" : "post"
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
module StrongParameters
|
156
|
-
protected
|
157
|
-
# Assigns params to the form and returns the model.
|
158
|
-
def assign(params, to:)
|
159
|
-
form = to
|
160
|
-
# TODO: Figure out how to render this in a way that doesn't concat a string; just throw everything away.
|
161
|
-
render_to_string form
|
162
|
-
form.assign params
|
163
|
-
form.model
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# Accept a collection of objects and map them to options suitable for form controls, like `select > options`
|
168
|
-
class OptionMapper
|
169
|
-
include Enumerable
|
170
|
-
|
171
|
-
def initialize(collection)
|
172
|
-
@collection = collection
|
173
|
-
end
|
174
|
-
|
175
|
-
def each(&options)
|
176
|
-
@collection.each do |object|
|
177
|
-
case object
|
178
|
-
in ActiveRecord::Relation => relation
|
179
|
-
active_record_relation_options_enumerable(relation).each(&options)
|
180
|
-
in id, value
|
181
|
-
options.call id, value
|
182
|
-
in value
|
183
|
-
options.call value, value.to_s
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
def active_record_relation_options_enumerable(relation)
|
189
|
-
Enumerator.new do |collection|
|
190
|
-
relation.each do |object|
|
191
|
-
attributes = object.attributes
|
192
|
-
id = attributes.delete(relation.primary_key)
|
193
|
-
value = attributes.values.join(" ")
|
194
|
-
collection << [ id, value ]
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
5
|
+
# When this is included in a Rails app, check if `Components::Base` is defined and
|
6
|
+
# inherit from that so we get all the users stuff; otherwise inherit from Phlex::HTML,
|
7
|
+
# which means we won't have all the users methods and overrides.
|
8
|
+
SUPERCLASSES = [
|
9
|
+
"::Components::Base", # Phlex 2.x base class in a Rails project
|
10
|
+
"::ApplicationComponent", # Phlex 1.x base class in a Rails project
|
11
|
+
"::Phlex::HTML", # Couldn't detect a base Phlex Rails class, so use Phlex::HTML
|
12
|
+
]
|
13
|
+
|
14
|
+
# Find the base class for the Rails app.
|
15
|
+
def self.base_class
|
16
|
+
const_get SUPERCLASSES.find { |const| const_defined?(const) }
|
198
17
|
end
|
199
18
|
|
200
|
-
|
201
|
-
|
202
|
-
attr_reader :field, :dom
|
203
|
-
|
204
|
-
delegate :dom, to: :field
|
205
|
-
|
206
|
-
def initialize(field, attributes: {})
|
207
|
-
@field = field
|
208
|
-
@attributes = attributes
|
209
|
-
end
|
210
|
-
|
211
|
-
def field_attributes
|
212
|
-
{}
|
213
|
-
end
|
214
|
-
|
215
|
-
def focus(value = true)
|
216
|
-
@attributes[:autofocus] = value
|
217
|
-
self
|
218
|
-
end
|
219
|
-
|
220
|
-
private
|
221
|
-
|
222
|
-
def attributes
|
223
|
-
field_attributes.merge(@attributes)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
class FieldComponent < BaseComponent
|
228
|
-
def field_attributes
|
229
|
-
{ id: dom.id, name: dom.name }
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
class LabelComponent < BaseComponent
|
234
|
-
def view_template(&content)
|
235
|
-
content ||= Proc.new { field.key.to_s.titleize }
|
236
|
-
label(**attributes, &content)
|
237
|
-
end
|
238
|
-
|
239
|
-
def field_attributes
|
240
|
-
{ for: dom.id }
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
class ButtonComponent < FieldComponent
|
245
|
-
def view_template(&content)
|
246
|
-
content ||= Proc.new { button_text }
|
247
|
-
button(**attributes, &content)
|
248
|
-
end
|
249
|
-
|
250
|
-
def button_text
|
251
|
-
@attributes.fetch(:value, dom.value).titleize
|
252
|
-
end
|
253
|
-
|
254
|
-
def field_attributes
|
255
|
-
{ id: dom.id, name: dom.name, value: dom.value }
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
class CheckboxComponent < FieldComponent
|
260
|
-
def view_template(&)
|
261
|
-
# Rails has a hidden and checkbox input to deal with sending back a value
|
262
|
-
# to the server regardless of if the input is checked or not.
|
263
|
-
input(name: dom.name, type: :hidden, value: "0")
|
264
|
-
# The hard coded keys need to be in here so the user can't overrite them.
|
265
|
-
input(type: :checkbox, value: "1", **attributes)
|
266
|
-
end
|
267
|
-
|
268
|
-
def field_attributes
|
269
|
-
{ id: dom.id, name: dom.name, checked: field.value }
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
class InputComponent < FieldComponent
|
274
|
-
def view_template(&)
|
275
|
-
input(**attributes)
|
276
|
-
end
|
277
|
-
|
278
|
-
def field_attributes
|
279
|
-
{
|
280
|
-
id: dom.id,
|
281
|
-
name: dom.name,
|
282
|
-
type: type,
|
283
|
-
value: value
|
284
|
-
}
|
285
|
-
end
|
286
|
-
|
287
|
-
def has_client_provided_value?
|
288
|
-
case type.to_s
|
289
|
-
when "file", "image"
|
290
|
-
true
|
291
|
-
else
|
292
|
-
false
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
def value
|
297
|
-
dom.value unless has_client_provided_value?
|
298
|
-
end
|
299
|
-
|
300
|
-
def type
|
301
|
-
@type ||= ActiveSupport::StringInquirer.new(attribute_type || value_type)
|
302
|
-
end
|
303
|
-
|
304
|
-
protected
|
305
|
-
def value_type
|
306
|
-
case field.value
|
307
|
-
when URI
|
308
|
-
"url"
|
309
|
-
when Integer, Float
|
310
|
-
"number"
|
311
|
-
when Date, DateTime
|
312
|
-
"date"
|
313
|
-
when Time
|
314
|
-
"time"
|
315
|
-
else
|
316
|
-
"text"
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
def attribute_type
|
321
|
-
if type = @attributes[:type] || @attributes["type"]
|
322
|
-
type.to_s
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
class TextareaComponent < FieldComponent
|
328
|
-
def view_template(&content)
|
329
|
-
content ||= Proc.new { dom.value }
|
330
|
-
textarea(**attributes, &content)
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
class SelectField < FieldComponent
|
335
|
-
def initialize(*, collection: [], **, &)
|
336
|
-
super(*, **, &)
|
337
|
-
@collection = collection
|
338
|
-
end
|
339
|
-
|
340
|
-
def view_template(&options)
|
341
|
-
if block_given?
|
342
|
-
select(**attributes, &options)
|
343
|
-
else
|
344
|
-
select(**attributes) { options(*@collection) }
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
def options(*collection)
|
349
|
-
map_options(collection).each do |key, value|
|
350
|
-
option(selected: field.value == key, value: key) { value }
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
def blank_option(&)
|
355
|
-
option(selected: field.value.nil?, &)
|
356
|
-
end
|
357
|
-
|
358
|
-
def true_option(&)
|
359
|
-
option(selected: field.value == true, value: true.to_s, &)
|
360
|
-
end
|
361
|
-
|
362
|
-
def false_option(&)
|
363
|
-
option(selected: field.value == false, value: false.to_s, &)
|
364
|
-
end
|
365
|
-
|
366
|
-
protected
|
367
|
-
def map_options(collection)
|
368
|
-
OptionMapper.new(collection)
|
369
|
-
end
|
370
|
-
end
|
371
|
-
end
|
19
|
+
# Set the base class for the rem
|
20
|
+
Component = base_class
|
372
21
|
end
|
373
|
-
end
|
22
|
+
end
|
data/lib/superform/version.rb
CHANGED
metadata
CHANGED
@@ -1,34 +1,28 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: superform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brad Gessler
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: phlex-rails
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
|
-
- - "
|
17
|
-
- !ruby/object:Gem::Version
|
18
|
-
version: '1.0'
|
19
|
-
- - "<"
|
16
|
+
- - "~>"
|
20
17
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
18
|
+
version: '2.0'
|
22
19
|
type: :runtime
|
23
20
|
prerelease: false
|
24
21
|
version_requirements: !ruby/object:Gem::Requirement
|
25
22
|
requirements:
|
26
|
-
- - "
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
version: '1.0'
|
29
|
-
- - "<"
|
23
|
+
- - "~>"
|
30
24
|
- !ruby/object:Gem::Version
|
31
|
-
version: '
|
25
|
+
version: '2.0'
|
32
26
|
- !ruby/object:Gem::Dependency
|
33
27
|
name: zeitwerk
|
34
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,17 +53,30 @@ files:
|
|
59
53
|
- LICENSE.txt
|
60
54
|
- README.md
|
61
55
|
- Rakefile
|
56
|
+
- SPEC_STYLE_GUIDE.md
|
62
57
|
- lib/generators/superform/install/USAGE
|
63
58
|
- lib/generators/superform/install/install_generator.rb
|
64
|
-
- lib/generators/superform/install/templates/
|
59
|
+
- lib/generators/superform/install/templates/base.rb
|
65
60
|
- lib/superform.rb
|
66
61
|
- lib/superform/dom.rb
|
67
62
|
- lib/superform/field.rb
|
68
63
|
- lib/superform/field_collection.rb
|
64
|
+
- lib/superform/form.rb
|
69
65
|
- lib/superform/namespace.rb
|
70
66
|
- lib/superform/namespace_collection.rb
|
71
67
|
- lib/superform/node.rb
|
72
68
|
- lib/superform/rails.rb
|
69
|
+
- lib/superform/rails/components/base.rb
|
70
|
+
- lib/superform/rails/components/button.rb
|
71
|
+
- lib/superform/rails/components/checkbox.rb
|
72
|
+
- lib/superform/rails/components/field.rb
|
73
|
+
- lib/superform/rails/components/input.rb
|
74
|
+
- lib/superform/rails/components/label.rb
|
75
|
+
- lib/superform/rails/components/select.rb
|
76
|
+
- lib/superform/rails/components/textarea.rb
|
77
|
+
- lib/superform/rails/form.rb
|
78
|
+
- lib/superform/rails/option_mapper.rb
|
79
|
+
- lib/superform/rails/strong_parameters.rb
|
73
80
|
- lib/superform/version.rb
|
74
81
|
- sig/superform.rbs
|
75
82
|
homepage: https://github.com/rubymonolith/superform
|
@@ -94,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
101
|
- !ruby/object:Gem::Version
|
95
102
|
version: '0'
|
96
103
|
requirements: []
|
97
|
-
rubygems_version: 3.6.
|
104
|
+
rubygems_version: 3.6.7
|
98
105
|
specification_version: 4
|
99
106
|
summary: Build forms in Rails
|
100
107
|
test_files: []
|
@@ -1,31 +0,0 @@
|
|
1
|
-
class ApplicationForm < Superform::Rails::Form
|
2
|
-
include Phlex::Rails::Helpers::Pluralize
|
3
|
-
|
4
|
-
def row(component)
|
5
|
-
div do
|
6
|
-
render component.field.label(style: "display: block;")
|
7
|
-
render component
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def around_template(&)
|
12
|
-
super do
|
13
|
-
error_messages
|
14
|
-
yield
|
15
|
-
submit
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def error_messages
|
20
|
-
if model.errors.any?
|
21
|
-
div(style: "color: red;") do
|
22
|
-
h2 { "#{pluralize model.errors.count, "error"} prohibited this post from being saved:" }
|
23
|
-
ul do
|
24
|
-
model.errors.each do |error|
|
25
|
-
li { error.full_message }
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|