forme 1.11.0 → 2.1.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 +54 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +235 -209
- data/Rakefile +1 -7
- data/lib/forme/bs3.rb +18 -4
- data/lib/forme/erb.rb +13 -25
- data/lib/forme/form.rb +144 -149
- data/lib/forme/input.rb +1 -1
- data/lib/forme/rails.rb +39 -83
- data/lib/forme/raw.rb +2 -2
- data/lib/forme/tag.rb +3 -12
- data/lib/forme/template.rb +110 -0
- data/lib/forme/transformers/formatter.rb +4 -1
- data/lib/forme/transformers/helper.rb +0 -1
- data/lib/forme/transformers/inputs_wrapper.rb +4 -4
- data/lib/forme/version.rb +2 -2
- data/lib/forme.rb +15 -2
- data/lib/roda/plugins/forme.rb +1 -1
- data/lib/roda/plugins/forme_erubi_capture.rb +57 -0
- data/lib/roda/plugins/forme_route_csrf.rb +16 -34
- data/lib/roda/plugins/forme_set.rb +39 -76
- data/lib/sequel/plugins/forme.rb +40 -50
- data/lib/sequel/plugins/forme_i18n.rb +3 -1
- data/lib/sequel/plugins/forme_set.rb +3 -1
- data/spec/all.rb +1 -1
- data/spec/bs3_reference_spec.rb +18 -18
- data/spec/bs3_sequel_plugin_spec.rb +17 -17
- data/spec/bs3_spec.rb +23 -11
- data/spec/erb_helper.rb +69 -58
- data/spec/erubi_capture_helper.rb +198 -0
- data/spec/forme_spec.rb +21 -32
- data/spec/rails_integration_spec.rb +39 -25
- data/spec/roda_integration_spec.rb +118 -70
- data/spec/sequel_helper.rb +0 -1
- data/spec/sequel_i18n_helper.rb +1 -1
- data/spec/sequel_i18n_plugin_spec.rb +3 -2
- data/spec/sequel_plugin_spec.rb +29 -12
- data/spec/sequel_set_plugin_spec.rb +9 -2
- data/spec/shared_erb_specs.rb +71 -0
- data/spec/sinatra_integration_spec.rb +5 -6
- data/spec/spec_helper.rb +21 -8
- metadata +9 -7
- data/lib/forme/erb_form.rb +0 -74
- data/lib/forme/sinatra.rb +0 -17
data/README.rdoc
CHANGED
@@ -6,91 +6,75 @@ Forme is a HTML forms library for ruby with the following goals:
|
|
6
6
|
2. Have a simple API
|
7
7
|
3. Support forms both with and without related objects
|
8
8
|
4. Allow compiling down to different types of output
|
9
|
+
5. Integrate easily into web frameworks
|
9
10
|
|
10
11
|
= Introduction
|
11
12
|
|
12
13
|
Forme is designed to make creating HTML forms easier. Flexibility and
|
13
|
-
|
14
|
-
|
15
|
-
to return html strings for widgets, but it could also be used for
|
16
|
-
serializing to other formats, or even as a DSL for a GUI application.
|
14
|
+
ease of use are the primary objectives. Here's a basic example,
|
15
|
+
showing usage without a related object:
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
is that <tt>Forme::Tag</tt> directly represents the underlying html
|
26
|
-
tag, containing a type, optional attributes, and children, while the
|
27
|
-
<tt>Forme::Input</tt> is more abstract and attempts to be user friendly.
|
28
|
-
For example, these both compile by default to the same select tag:
|
17
|
+
Forme.form({:action=>'/foo'}) do |f|
|
18
|
+
f.input(:text, :name=>'bar')
|
19
|
+
f.tag(:fieldset) do
|
20
|
+
f.input(:textarea, :name=>'baz')
|
21
|
+
end
|
22
|
+
f.button('Update')
|
23
|
+
end
|
29
24
|
|
30
|
-
|
31
|
-
# or
|
32
|
-
f.tag(:select, {}, [f.tag(:option, {:value=>1}, ['foo'])])
|
25
|
+
This results in the following HTML:
|
33
26
|
|
34
|
-
|
35
|
-
|
27
|
+
<form action="/foo">
|
28
|
+
<input name="bar" type="text"/>
|
29
|
+
<fieldset>
|
30
|
+
<textarea name="baz"></textarea>
|
31
|
+
</fieldset>
|
32
|
+
<input type="submit" value="Update"/>
|
33
|
+
</form>
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
+Helper+ :: If the <tt>Forme::Input</tt> instance has any help text,
|
42
|
-
adds the help text in a separate tag.
|
43
|
-
+Labeler+ :: If the <tt>Forme::Input</tt> instance has a label,
|
44
|
-
takes the formatted output and labels it.
|
45
|
-
+Wrapper+ :: Takes the output of the formatter, labeler, and
|
46
|
-
error_handler transformers, and wraps it in another tag (or just
|
47
|
-
returns it unmodified).
|
48
|
-
+Serializer+ :: converts a <tt>Forme::Tag</tt> instance into an
|
49
|
-
html string.
|
50
|
-
|
51
|
-
Technically, only the +Serializer+ is necessary. The <tt>Forme::Form#input</tt>
|
52
|
-
and <tt>Forme::Form#tag</tt> methods return +Input+ and +Tag+ objects. These objects
|
53
|
-
both have +to_s+ defined to call the appropriate +Serializer+ with
|
54
|
-
themselves. The +Serializer+ calls the appropriate +Formatter+ if
|
55
|
-
it encounters an +Input+ instance, and attempts to serialize the
|
56
|
-
output of that (which is usually a +Tag+ instance). It is up to
|
57
|
-
the +Formatter+ to call the +Labeler+, +ErrorHandler+, +Helper+,
|
58
|
-
and/or +Wrapper+.
|
59
|
-
|
60
|
-
The <tt>Forme::Form</tt> object takes the 6 transformers as options (:formatter,
|
61
|
-
:labeler, :error_handler, :helper, :wrapper, :inputs_wrapper, and :serializer), all of which
|
62
|
-
should be objects responding to +call+ (so you can use +Proc+s) or be symbols
|
63
|
-
registered with the library using <tt>Forme.register_transformer</tt>:
|
35
|
+
Forme also supports forms that are associated with objects, and
|
36
|
+
has specific support for Sequel::Model objects to allow easily building
|
37
|
+
forms for such objects. The Sequel support handles inputs based on
|
38
|
+
database columns, and automatically handles labels and errors:
|
64
39
|
|
65
|
-
Forme.
|
66
|
-
input
|
40
|
+
Forme.form(Album[1], action: '/foo') do |f|
|
41
|
+
f.input :name
|
42
|
+
f.input :copies_sold
|
67
43
|
end
|
68
44
|
|
69
|
-
|
70
|
-
is a <tt>Forme::Tag</tt> instance, and +input+ is a <tt>Forme::Input</tt>
|
71
|
-
instance. The +Formatter+ and +Serializer+ transformers are the two
|
72
|
-
exceptions, with +Formatter+ being called with just an +input+, and
|
73
|
-
+Serializer+ potentionally being called with any object. The +Serializer+
|
74
|
-
will in general recursively call itself with children of the argument
|
75
|
-
given.
|
76
|
-
|
77
|
-
There is also an +InputsWrapper+ transformer, that is called by
|
78
|
-
<tt>Forme::Form#inputs</tt>. It's used to wrap up a group of
|
79
|
-
related options (in a fieldset by default). It takes +form+
|
80
|
-
(<tt>Forme::Form</tt> instance) and +input_opts+ (+Hash+) arguments.
|
45
|
+
This results in the following HTML:
|
81
46
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
47
|
+
<form action="/foo" method="post">
|
48
|
+
<label>Name:
|
49
|
+
<input id="album_name" name="album[name]" type="text" value="Rising Force"/>
|
50
|
+
</label>
|
51
|
+
<label>Copies Sold:
|
52
|
+
<input id="album_copies_sold" name="album[copies_sold]" type="number" value="100000"/>
|
53
|
+
</label>
|
54
|
+
</form>
|
86
55
|
|
87
|
-
|
88
|
-
|
56
|
+
In addition to integrating with Sequel, Form also integrates into
|
57
|
+
three separate web frameworks, Roda, Rails, and Sinatra, allowing
|
58
|
+
use of forms inside templates. This is the most common usage of Forme.
|
59
|
+
|
60
|
+
One distinct advantage of Forme over other form libraries is the use
|
61
|
+
of an abstract syntax tree internally, allowing the same form code to
|
62
|
+
compile to different HTML with different options. For example, it
|
63
|
+
allows using the exactly same form code to display a form you can modify
|
64
|
+
as well as a read-only view, just by passing a single option when
|
65
|
+
creating the form. For example, with the first example in this section,
|
66
|
+
if you pass the <tt>formatter: :readonly</tt> option, you get the
|
67
|
+
following HTML instead:
|
68
|
+
|
69
|
+
<form action="/foo">
|
70
|
+
<span class="readonly-text"></span>
|
71
|
+
<fieldset>
|
72
|
+
<div class="readonly-textarea"></div>
|
73
|
+
</fieldset>
|
74
|
+
</form>
|
89
75
|
|
90
|
-
|
91
|
-
|
92
|
-
Forme::Labeler::Explicit.new.call(tag, input)
|
93
|
-
end
|
76
|
+
This allows you to reuse the same form code in multiple contexts,
|
77
|
+
which can save considerable development time.
|
94
78
|
|
95
79
|
= Installation
|
96
80
|
|
@@ -101,13 +85,12 @@ by creating your own transformer and then calling the existing transformer.
|
|
101
85
|
Demo Site :: http://forme-demo.jeremyevans.net
|
102
86
|
RDoc :: http://forme.jeremyevans.net
|
103
87
|
Source :: https://github.com/jeremyevans/forme
|
104
|
-
|
105
|
-
Google Group :: https://groups.google.com/forum/#!forum/ruby-forme
|
88
|
+
Discussion Forum :: https://github.com/jeremyevans/forme/discussions
|
106
89
|
Bug Tracker :: https://github.com/jeremyevans/forme/issues
|
107
90
|
|
108
|
-
=
|
91
|
+
= Direct Instantiation
|
109
92
|
|
110
|
-
|
93
|
+
While not typically done, you can instantiate Forme::Form objects directly and use them:
|
111
94
|
|
112
95
|
f = Forme::Form.new
|
113
96
|
f.open(:action=>'/foo', :method=>:post) # '<form action="/foo" method="post">'
|
@@ -130,47 +113,11 @@ on the object (or using #[] if the object is a hash).
|
|
130
113
|
f = Forme::Form.new([:foo])
|
131
114
|
f.input(:first) # '<input id="first" name="first" type="text" value="foo"/>'
|
132
115
|
|
133
|
-
= DSL
|
134
|
-
|
135
|
-
Forme comes with a DSL:
|
136
|
-
|
137
|
-
Forme.form(:action=>'/foo') do |f|
|
138
|
-
f.input(:text, :name=>'bar')
|
139
|
-
f.tag(:fieldset) do
|
140
|
-
f.input(:textarea, :name=>'baz')
|
141
|
-
end
|
142
|
-
f.button('Update')
|
143
|
-
end
|
144
|
-
# <form action="/foo">
|
145
|
-
# <input name="bar" type="text"/>
|
146
|
-
# <fieldset>
|
147
|
-
# <textarea name="baz"></textarea>
|
148
|
-
# </fieldset>
|
149
|
-
# <input type="submit" value="Update"/>
|
150
|
-
# </form>
|
151
|
-
|
152
|
-
You can wrap up multiple inputs with the <tt>:inputs</tt> method:
|
153
|
-
|
154
|
-
Forme.form(:action=>'/foo') do |f|
|
155
|
-
f.inputs([[:text, {:name=>'bar'}], [:textarea, {:name=>'baz'}]])
|
156
|
-
end
|
157
|
-
# <form action="/foo">
|
158
|
-
# <fieldset class="inputs">
|
159
|
-
# <input name="bar" type="text"/>
|
160
|
-
# <textarea name="baz"></textarea>
|
161
|
-
# </fieldset>
|
162
|
-
# </form>
|
163
|
-
|
164
|
-
You can even do everything in a single method call:
|
165
|
-
|
166
|
-
Forme.form({:action=>'/foo'},
|
167
|
-
:inputs=>[[:text, {:name=>'bar'}], [:textarea, {:name=>'baz'}]])
|
168
|
-
|
169
116
|
= Forme::Form Creation
|
170
117
|
|
171
|
-
|
172
|
-
|
173
|
-
|
118
|
+
+Forme.form+ takes up to 3 arguments, and yields the Forme::Form
|
119
|
+
object to the block (if given). Here are the argument styles that you can
|
120
|
+
use for +Forme.form+.
|
174
121
|
|
175
122
|
No args :: Creates a +Form+ object with no options and not associated
|
176
123
|
to an +obj+, and with no attributes in the opening tag.
|
@@ -190,21 +137,21 @@ Examples:
|
|
190
137
|
Forme.form
|
191
138
|
|
192
139
|
# 1 hash argument (attributes)
|
193
|
-
Forme.form(:
|
140
|
+
Forme.form(action: '/foo')
|
194
141
|
|
195
142
|
# 1 non-hash argument (a reference object used when building the form)
|
196
143
|
Forme.form(Album[1])
|
197
144
|
|
198
145
|
# 2 hash arguments (attributes, and options)
|
199
|
-
Forme.form({:
|
146
|
+
Forme.form({action: '/foo'}, values: params)
|
200
147
|
|
201
148
|
# 1 non-hash argument, 1-2 hash arguments (ref obj, attributes, options)
|
202
|
-
Forme.form(Album[1], :
|
203
|
-
Forme.form(Album[1], {:
|
149
|
+
Forme.form(Album[1], action: '/foo')
|
150
|
+
Forme.form(Album[1], {action: '/foo'}, values: params)
|
204
151
|
|
205
152
|
If you want a Forme::Form instance where the reference object is a Hash, then you need to pass the hash object using the :obj option:
|
206
153
|
|
207
|
-
Forme.form({:
|
154
|
+
Forme.form({action: '/foo'}, obj: {foo: 'bar'})
|
208
155
|
|
209
156
|
You can also create Forme::Form objects the normal ruby way using Forme::Form#new. The
|
210
157
|
difference between Forme::Form#new and Forme.form is that Forme.form includes the enclosing
|
@@ -215,13 +162,13 @@ a hash of <form> tag attributes, so it has the following API:
|
|
215
162
|
Forme::Form.new
|
216
163
|
|
217
164
|
# 1 hash argument
|
218
|
-
Forme::Form.new(:
|
165
|
+
Forme::Form.new(values: params)
|
219
166
|
|
220
167
|
# 1 non-hash argument
|
221
168
|
Forme::Form.new(Album[1])
|
222
169
|
|
223
170
|
# 1 non-hash argument, 1-2 hash arguments
|
224
|
-
Forme::Form.new(Album[1], :
|
171
|
+
Forme::Form.new(Album[1], values: params)
|
225
172
|
|
226
173
|
= Forme::Form Methods
|
227
174
|
|
@@ -230,9 +177,9 @@ a hash of <form> tag attributes, so it has the following API:
|
|
230
177
|
If you create a Form via Forme::Forme#new, you can use the form method to create a form tag:
|
231
178
|
|
232
179
|
f = Forme::Form.new
|
233
|
-
f.form(:
|
180
|
+
f.form(action: '/foo')
|
234
181
|
|
235
|
-
This is what Forme.form uses internally to create the
|
182
|
+
This is what Forme.form uses internally to create the +<form>+ tag
|
236
183
|
|
237
184
|
== input
|
238
185
|
|
@@ -285,8 +232,8 @@ Which results in a form similar to the following:
|
|
285
232
|
|
286
233
|
== inputs
|
287
234
|
|
288
|
-
This wraps multiple inputs in a tag (it uses the inputs_wrapper transformer discussed below,
|
289
|
-
so it uses a fieldset by default). You can give the inputs to add as an enumerable argument:
|
235
|
+
This wraps multiple inputs in a tag (it uses the +:inputs_wrapper+ transformer discussed below,
|
236
|
+
so it uses a +fieldset+ by default). You can give the inputs to add as an enumerable argument:
|
290
237
|
|
291
238
|
f.inputs([:textarea, [:text, :value=>'a']])
|
292
239
|
# <fieldset>
|
@@ -300,13 +247,13 @@ You can also provide a block:
|
|
300
247
|
f.input(:text, :value=>'a')
|
301
248
|
end
|
302
249
|
|
303
|
-
Any options given are passed to the inputs_wrapper (so you can use options such as
|
304
|
-
to set a legend for the fieldset), and also to the
|
305
|
-
such as
|
250
|
+
Any options given are passed to the +inputs_wrapper+ (so you can use options such as +:legend+
|
251
|
+
to set a legend for the fieldset), and also to the +with_opts+ method (so you can use options
|
252
|
+
such as +:wrapper+ to modify the default wrapper transformer for inputs inside the block).
|
306
253
|
There is also one option specific to the inputs method:
|
307
254
|
|
308
255
|
:nested_inputs_wrapper :: Sets the default inputs_wrapper to use for calls to inputs inside
|
309
|
-
the block. The reason for this option is that
|
256
|
+
the block. The reason for this option is that +:inputs_wrapper+
|
310
257
|
option affects the current call to inputs, so if you want to
|
311
258
|
use a different inputs_wrapper for nested calls, you need this option.
|
312
259
|
|
@@ -324,30 +271,31 @@ It can be called with a string to provide a value for the button:
|
|
324
271
|
|
325
272
|
It can be called with a hash to provide options for the submit input:
|
326
273
|
|
327
|
-
f.button(:
|
274
|
+
f.button(value: 'Search', class: 'btn')
|
328
275
|
# <input class="btn" type="submit" value="Search"/>
|
329
276
|
|
330
277
|
== with_opts
|
331
278
|
|
332
|
-
This requires a block, and modifies the Form's options inside the block,
|
279
|
+
This requires a block, and modifies the Forme::Form's options inside the block,
|
333
280
|
restoring the options when the block returns:
|
334
281
|
|
335
282
|
f.input(:text)
|
336
283
|
# <input type="text"/>
|
337
|
-
|
284
|
+
|
285
|
+
f.with_opts(wrapper: :li) do
|
338
286
|
f.input(:text)
|
339
287
|
end
|
340
288
|
# <li><input type="text"/></li>
|
341
289
|
|
342
|
-
This supports most options you can provide to
|
290
|
+
This supports most options you can provide to Forme::Form, but not all.
|
343
291
|
|
344
292
|
== with_obj
|
345
293
|
|
346
|
-
This uses with_opts to change the Form
|
294
|
+
This uses +with_opts+ to change the Forme::Form object temporarily. It
|
347
295
|
yields the object to the block, and also supports appending to the
|
348
296
|
existing namespaces:
|
349
297
|
|
350
|
-
Forme.form([:foo], :namespace
|
298
|
+
Forme.form([:foo], {action: '/path'}, namespace: 'a') do |f|
|
351
299
|
f.input(:first)
|
352
300
|
# <input id="a_first" name="a[first]" type="text" value="foo"/>
|
353
301
|
f.with_obj(['foobar'], 'b') do |o|
|
@@ -358,11 +306,11 @@ existing namespaces:
|
|
358
306
|
|
359
307
|
== each_obj
|
360
308
|
|
361
|
-
This allows you to provide an object-yielding enumerable.
|
362
|
-
each object in the enumerable. It yields each object as well as the
|
363
|
-
object in the enumerable, and includes the index in the namespace:
|
309
|
+
This allows you to provide an object-yielding enumerable. +each_object+ will call
|
310
|
+
+with_obj+ with each object in the enumerable. It yields each object as well as the
|
311
|
+
index of the object in the enumerable, and includes the index in the namespace:
|
364
312
|
|
365
|
-
objectlist = ['foobar', ['good']]
|
313
|
+
objectlist = [['foobar'], ['good']]
|
366
314
|
Forme.form([:foo], :namespace=>'a') do |f|
|
367
315
|
f.each_obj(objectlist, 'b') do |o, i|
|
368
316
|
f.input(:first, :size=>10+i)
|
@@ -377,7 +325,7 @@ Forme ships with a Sequel plugin (use <tt>Sequel::Model.plugin :forme</tt> to en
|
|
377
325
|
Sequel::Model instances support the +forme_config+ and +forme_input+ methods and return customized inputs.
|
378
326
|
An additional instance method, +forme_namespace+ can optionally be defined to customize how model classnames
|
379
327
|
are transformed into form classes and input IDs and names. This can be useful if your Sequel::Model classes
|
380
|
-
are nested under a parent namespace.
|
328
|
+
are nested under a parent namespace. The default namespace uses Sequel::Model#underscore.
|
381
329
|
|
382
330
|
module Admin
|
383
331
|
class Albums < Sequel::Model
|
@@ -387,27 +335,11 @@ are nested under a parent namespace. It falls back to the behaviour of Sequel::M
|
|
387
335
|
end
|
388
336
|
end
|
389
337
|
|
390
|
-
|
391
|
-
|
392
|
-
The Sequel support handles inputs based on database columns, and automatically handles labels and errors.
|
393
|
-
|
394
|
-
Forme.form(Album[1], :action=>'/foo') do |f|
|
395
|
-
f.input :name
|
396
|
-
f.input :copies_sold
|
397
|
-
end
|
398
|
-
|
399
|
-
This will create a form similar to:
|
400
|
-
|
401
|
-
<form action="/foo" method="post">
|
402
|
-
<label>Name: <input id="album_name" name="album[name]" type="text" value="Rising Force"/></label>
|
403
|
-
<label>Copies Sold: <input id="album_copies_sold" name="album[copies_sold]" type="number" value="100000"/></label>
|
404
|
-
</form>
|
405
|
-
|
406
|
-
The Forme Sequel plugin also integerates with Sequel's validation reflection support with the
|
407
|
-
+validation_class_methods+ plugin that ships with Sequel. It will add +pattern+ and +maxlength+ attributes
|
338
|
+
The Sequel :forme plugin also integerates with Sequel's validation reflection support that comes with the
|
339
|
+
Sequel validation_class_methods plugin. It will add +pattern+ and +maxlength+ attributes
|
408
340
|
based on the format, numericality, and length validations.
|
409
341
|
|
410
|
-
==
|
342
|
+
== Specialized input options for specific column types
|
411
343
|
|
412
344
|
In addition to the default Forme options, the Sequel support includes, for specific column types,
|
413
345
|
these additional options to the #input method:
|
@@ -569,7 +501,7 @@ One way to handle the form submission is to use Sequel::Model#set_fields.
|
|
569
501
|
Note that you have to specify the parameter names again as the second argument to
|
570
502
|
set_fields.
|
571
503
|
|
572
|
-
Handling
|
504
|
+
Handling submitted parameters becomes more complex as your forms become more complex.
|
573
505
|
For example, if you are only displaying certain form fields in certain situations:
|
574
506
|
|
575
507
|
album = Album[1]
|
@@ -589,9 +521,9 @@ As you can see, you basically need to recreate the conditionals used when creati
|
|
589
521
|
the form, so that that the processing of the form submission handles only the
|
590
522
|
inputs that were displayed on the form.
|
591
523
|
|
592
|
-
=== forme_set
|
524
|
+
=== Sequel forme_set plugin
|
593
525
|
|
594
|
-
The forme_set plugin is designed to make handling form submissions easier. What it does
|
526
|
+
The Sequel forme_set plugin is designed to make handling form submissions easier. What it does
|
595
527
|
is record the form fields that are used on the object, and then it uses those fields
|
596
528
|
to handle input submitted for the object. For example:
|
597
529
|
|
@@ -670,12 +602,12 @@ this is specific to the web framework you are using, but is it similar to:
|
|
670
602
|
|
671
603
|
forme_set is not perfect, there are ways to use Forme that forme_set will not handle
|
672
604
|
correctly. First, forme_set only works with forms that use model objects, and doesn't
|
673
|
-
handle inputs where the
|
605
|
+
handle inputs where the +:obj+ option is provided to change the input.
|
674
606
|
Additionally, forme_set does not currently handle subform/nested_attributes.
|
675
607
|
|
676
|
-
In cases where forme_set does not handle things correctly, you can use forme_parse
|
677
|
-
which will return metadata that forme_set uses (forme_set calls forme_parse
|
678
|
-
internally). forme_parse returns a hash with the following keys:
|
608
|
+
In cases where forme_set does not handle things correctly, you can use +forme_parse+,
|
609
|
+
which will return metadata that +forme_set+ uses (+forme_set+ calls +forme_parse+
|
610
|
+
internally). +forme_parse+ returns a hash with the following keys:
|
679
611
|
|
680
612
|
:values :: A hash of values that can be used to update the model, suitable for passing
|
681
613
|
to Sequel::Model#set.
|
@@ -683,21 +615,21 @@ internally). forme_parse returns a hash with the following keys:
|
|
683
615
|
check that the submitted values for associated objects match one of the
|
684
616
|
options for the input in the form.
|
685
617
|
|
686
|
-
It is possible to use forme_set for the values it can handle, and set other fields manually
|
687
|
-
using set_fields
|
618
|
+
It is possible to use +forme_set+ for the values it can handle, and set other fields manually
|
619
|
+
using +set_fields+.
|
688
620
|
|
689
|
-
=== forme_set
|
621
|
+
=== Roda forme_set plugin
|
690
622
|
|
691
|
-
The forme_set
|
692
|
-
handling form submissions even easier. This plugin
|
693
|
-
fields were used to build the form, as well as some other metadata. It
|
623
|
+
The Roda forme_set plugin builds on the Sequel forme_set plugin and is designed to make
|
624
|
+
handling form submissions even easier. This plugin adds a hidden form input to store which
|
625
|
+
fields were used to build the form, as well as some other metadata. It adds another hidden
|
694
626
|
form input with an HMAC, so that on submission, if the HMAC matches, you can be sure that an
|
695
627
|
attacker didn't add extra fields.
|
696
628
|
|
697
629
|
There are a couple advantages to this plugin over using just the Sequel forme_set plugin.
|
698
630
|
One is that you do not need to record the form fields when processing the submission of a
|
699
631
|
form, since the information you need is included in the form submission. Another is that
|
700
|
-
calling the forme_set method is simpler, since it can determine the necessary parameters.
|
632
|
+
calling the +forme_set+ method is simpler, since it can determine the necessary parameters.
|
701
633
|
|
702
634
|
While you need code like this when using just the Sequel forme_set plugin:
|
703
635
|
|
@@ -824,20 +756,20 @@ plugin to handle form submissions involving multiple objects, or for the
|
|
824
756
|
objects that were not passed when creating the form.
|
825
757
|
|
826
758
|
Second, the Roda forme_set plugin does not handle cases where the field values
|
827
|
-
are placed outside the
|
759
|
+
are placed outside the form's default namespace. The Sequel forme_set plugin
|
828
760
|
can handle those issues, as long as all values are in the same namespace, since
|
829
761
|
the Sequel forme_set plugin requires you pass in the specific hash to use (the
|
830
|
-
Roda forme_set plugin
|
762
|
+
Roda forme_set plugin uses the form's namespace information and the submitted
|
831
763
|
parameters to determine the hash to use).
|
832
764
|
|
833
765
|
In cases where the Roda forme_set does not handle things correctly, you can use
|
834
766
|
forme_parse, which will return metadata in the same format as the Sequel plugin
|
835
|
-
forme_parse method, with the addition of a
|
767
|
+
forme_parse method, with the addition of a +:form_version+ key in the hash for the
|
836
768
|
form version.
|
837
769
|
|
838
770
|
It is possible to use the Roda forme_set plugin for the submissions it can handle, the
|
839
771
|
Sequel forme_set plugin for the submissions it can handle, and set other fields manually
|
840
|
-
using the Sequel set_fields methods.
|
772
|
+
using the Sequel +set_fields+ methods.
|
841
773
|
|
842
774
|
Note that when using the Roda forme_set plugin with an existing form, you should first
|
843
775
|
enable the Roda plugin without actually using the Roda forme_set method. Do not
|
@@ -855,7 +787,15 @@ forme_i18n :: Handles translations for labels using i18n.
|
|
855
787
|
|
856
788
|
= Roda Support
|
857
789
|
|
858
|
-
Forme ships with
|
790
|
+
Forme ships with multiple Roda plugins
|
791
|
+
|
792
|
+
* forme_set (discussed above)
|
793
|
+
* forme
|
794
|
+
* forme_route_csrf
|
795
|
+
* forme_erubi_capture
|
796
|
+
|
797
|
+
== forme_route_csrf and forme plugins
|
798
|
+
|
859
799
|
For new code, it is recommended to use forme_route_csrf, as that uses Roda's route_csrf
|
860
800
|
plugin, which supports more secure request-specific CSRF tokens. In both cases, usage in ERB
|
861
801
|
templates is the same:
|
@@ -882,14 +822,29 @@ The forme plugin does not require any csrf plugin, but will transparently use
|
|
882
822
|
Rack::Csrf if it is available. If Rack::Csrf is available a CSRF tag if the form's
|
883
823
|
method is +POST+, with no configuration ability.
|
884
824
|
|
885
|
-
|
825
|
+
== forme_erubi_capture plugin
|
826
|
+
|
827
|
+
The forme_erubi_capture plugin builds on the forme_route_csrf plugin, but it supports
|
828
|
+
the erubi/capture_end engine, which allows this syntax:
|
829
|
+
|
830
|
+
<%|= form(@obj, :action=>'/foo') do |f| %>
|
831
|
+
<%= f.input(:field) %>
|
832
|
+
<%|= f.tag(:fieldset) do %>
|
833
|
+
<%= f.input(:field_two) %>
|
834
|
+
<%| end %>
|
835
|
+
<%| end %>
|
836
|
+
|
837
|
+
If you use the forme_erubi_capture plugin, you need to manually set Roda to use the
|
838
|
+
erubi/capture_end engine, which you can do via:
|
839
|
+
|
840
|
+
require 'erubi/capture_end'
|
841
|
+
app.plugin :render, :engine_opts=>{'erb'=>{:engine_class=>Erubi::CaptureEndEngine}}
|
886
842
|
|
887
|
-
|
888
|
-
injecting output (+@_out_buf+ by default).
|
843
|
+
The forme_erubi_capture plugin requires Roda 3.50.0+.
|
889
844
|
|
890
845
|
= Sinatra Support
|
891
846
|
|
892
|
-
Forme ships with a
|
847
|
+
Forme ships with a Sinatra extension that you can get by <tt>require "forme/erb"</tt> and using
|
893
848
|
<tt>including Forme::ERB::Helper</tt>. This is tested to support ERB templates in Sinatra.
|
894
849
|
It allows you to use the following API in your erb templates:
|
895
850
|
|
@@ -900,8 +855,8 @@ It allows you to use the following API in your erb templates:
|
|
900
855
|
<% end %>
|
901
856
|
<% end %>
|
902
857
|
|
903
|
-
In order to this to work transparently, the ERB outvar needs to be <tt>@_out_buf</tt
|
904
|
-
|
858
|
+
In order to this to work transparently, the ERB outvar needs to be <tt>@_out_buf</tt> (this is the
|
859
|
+
default in Sinatra).
|
905
860
|
|
906
861
|
= Rails Support
|
907
862
|
|
@@ -916,7 +871,7 @@ in your Rails forms:
|
|
916
871
|
<% end %>
|
917
872
|
<% end %>
|
918
873
|
|
919
|
-
This has been tested on Rails 3.2-
|
874
|
+
This has been tested on Rails 3.2-7.0.
|
920
875
|
|
921
876
|
= Input Types and Options
|
922
877
|
|
@@ -927,8 +882,8 @@ created via Forme::Form#input:
|
|
927
882
|
|
928
883
|
These options are supported by all of the input types:
|
929
884
|
|
930
|
-
:attr :: The attributes hash to use for the given tag,
|
931
|
-
other options that set attributes.
|
885
|
+
:attr :: The attributes hash to use for the given tag, attributes in this hash
|
886
|
+
take precedence over other options that set attributes.
|
932
887
|
:autofocus :: Set the autofocus attribute if true
|
933
888
|
:class :: A class to use. Unlike other options, this is combined with the
|
934
889
|
classes set in the :attr hash.
|
@@ -940,6 +895,7 @@ These options are supported by all of the input types:
|
|
940
895
|
:disabled :: Set the disabled attribute if true
|
941
896
|
:error :: Set an error message, invoking the error_handler
|
942
897
|
:error_handler :: Set a custom error_handler, overriding the form's default
|
898
|
+
:help :: Set help text to use, invoking the helper
|
943
899
|
:helper :: Set a custom helper, overriding the form's default
|
944
900
|
:id :: The id attribute to use
|
945
901
|
:key :: The base to use for the name and id attributes, based on the current
|
@@ -956,7 +912,7 @@ These options are supported by all of the input types:
|
|
956
912
|
for textarea tags, or the selected option(s) for select tags.
|
957
913
|
:wrapper :: Set a custom wrapper, overriding the form's default
|
958
914
|
|
959
|
-
== Input
|
915
|
+
== Input Type-Specific Options
|
960
916
|
|
961
917
|
=== :checkbox
|
962
918
|
|
@@ -974,18 +930,21 @@ Creates an input tag with type radio. Options:
|
|
974
930
|
|
975
931
|
=== :date / :datetime
|
976
932
|
|
977
|
-
By default, creates an input tag with type date or datetime. With the :
|
933
|
+
By default, creates an input tag with type date or datetime. With the <tt>as: :select</tt> option,
|
978
934
|
creates multiple select options. Options:
|
979
935
|
|
980
936
|
:as :: When value is :select, uses 3 or 6 select boxes by default.
|
981
|
-
:order :: The order of select boxes when using :
|
937
|
+
:order :: The order of select boxes when using <tt>as: :select</tt>. Entries should be a symbol
|
982
938
|
for the select field and string to use a string
|
983
939
|
(:date default: <tt>[:year, '-', :month, '-', :day]</tt>)
|
984
940
|
(:datetime default: <tt>[:year, '-', :month, '-', :day, ' ', :hour, ':', :minute, ':', :second]</tt>)
|
985
941
|
:select_labels :: The labels to use for the select boxes. Should be a hash keyed by the
|
986
|
-
|
942
|
+
symbol used (e.g. <tt>{:month=>'Month'}</tt>). By default, no labels are used.
|
987
943
|
:select_options :: The options to use for the select boxes. Should be a hash keyed by the
|
988
|
-
symbol used in order (e.g. <tt>{:year=>1970..2020}</tt>)
|
944
|
+
symbol used in order (e.g. <tt>{:year=>1970..2020}</tt>). The values
|
945
|
+
can be a number used as both the value and the text of the option or
|
946
|
+
an array with two elements, the first of which is the value for the option
|
947
|
+
and the second of which is the text for the option.
|
989
948
|
|
990
949
|
=== :select
|
991
950
|
|
@@ -1005,7 +964,8 @@ Creates a select tag, containing option tags specified by the :options option.
|
|
1005
964
|
:options :: An enumerable of options used for creating option tags.
|
1006
965
|
If the :text_method and :value_method are not given and the entry is an
|
1007
966
|
array, uses the first entry of the array as the text of the option, and
|
1008
|
-
the
|
967
|
+
the last entry of the array as the value of the option. If the last entry
|
968
|
+
of the array is a hash, uses the hash as the attributes for the option.
|
1009
969
|
:selected :: The value that should be selected. Any options that are equal to
|
1010
970
|
this value (or included in this value if a multiple select box),
|
1011
971
|
are set to selected.
|
@@ -1019,7 +979,7 @@ Creates a select tag, containing option tags specified by the :options option.
|
|
1019
979
|
=== :checkboxset
|
1020
980
|
|
1021
981
|
Creates a set of checkbox inputs all using the same name. Supports the same options
|
1022
|
-
as the select type, except that the :multiple option is assumed to be true. Also supports
|
982
|
+
as the :select type, except that the :multiple option is assumed to be true. Also supports
|
1023
983
|
the following options:
|
1024
984
|
|
1025
985
|
:tag_wrapper :: The wrapper transformer for individual tags in the set
|
@@ -1051,6 +1011,10 @@ as text and password, as well as newer HTML5 inputs such as number or email. Opt
|
|
1051
1011
|
These are the options supported by Forme::Form object, mostly used to set
|
1052
1012
|
the defaults for Inputs created via the form:
|
1053
1013
|
|
1014
|
+
:after :: A callable object that is yielded the Form instance after yielding to
|
1015
|
+
the block. Can be used to add hidden inputs to the end of the form.
|
1016
|
+
:before :: A callable object that is yielded the Form instance before yielding to
|
1017
|
+
the block. Can be used to add hidden inputs to the start of the form.
|
1054
1018
|
:config :: The configuration to use, which automatically sets defaults
|
1055
1019
|
for the transformers to use.
|
1056
1020
|
:errors :: A Hash of errors from a previous form submission, used to set
|
@@ -1058,7 +1022,6 @@ the defaults for Inputs created via the form:
|
|
1058
1022
|
:error_handler :: Sets the default error_handler for the form's inputs
|
1059
1023
|
:helper :: Sets the default helper for the form's inputs
|
1060
1024
|
:formatter :: Sets the default formatter for the form's inputs
|
1061
|
-
:hidden_tags :: Sets the hidden tags to automatically add to this form, see below.
|
1062
1025
|
:input_defaults :: Sets the default options for each input type. This should
|
1063
1026
|
be a hash with input type keys, where the values are the
|
1064
1027
|
hash of default options to use for the input type.
|
@@ -1079,17 +1042,7 @@ For forms created by Forme.form, the following options are supported:
|
|
1079
1042
|
to the block.
|
1080
1043
|
:button :: A button to add to the form, after yielding to the block.
|
1081
1044
|
|
1082
|
-
|
1083
|
-
|
1084
|
-
This should be an array, where elements are one of the following types:
|
1085
|
-
|
1086
|
-
String, Array, Forme::Tag :: Added directly as a child of the form tag.
|
1087
|
-
Hash :: Adds a hidden tag for each entry, with keys as the name of the hidden
|
1088
|
-
tag and values as the value of the hidden tag.
|
1089
|
-
Proc :: Will be called with the form tag object, and should return an instance
|
1090
|
-
of one of the handled types (or nil to not add a tag).
|
1091
|
-
|
1092
|
-
= Basic Design
|
1045
|
+
= Internal Architecture
|
1093
1046
|
|
1094
1047
|
Internally, Forme builds an abstract syntax tree of objects that
|
1095
1048
|
represent the form. The abstract syntax tree goes through a
|
@@ -1099,15 +1052,88 @@ strings. Here are the main classes used by the library:
|
|
1099
1052
|
|
1100
1053
|
<tt>Forme::Form</tt> :: main object
|
1101
1054
|
<tt>Forme::Input</tt> :: high level abstract tag (a single +Input+ could represent a select box with a bunch of options)
|
1102
|
-
<tt>Forme::Tag</tt> :: low level abstract tag representing an
|
1055
|
+
<tt>Forme::Tag</tt> :: low level abstract tag representing an HTML tag (there would be a separate +Tag+ for each option in a select box)
|
1056
|
+
|
1057
|
+
The difference between <tt>Forme::Input</tt> and <tt>Forme::Tag</tt>
|
1058
|
+
is that <tt>Forme::Tag</tt> directly represents the underlying HTML
|
1059
|
+
tag, containing a type, optional attributes, and children, while the
|
1060
|
+
<tt>Forme::Input</tt> is more abstract and attempts to be user friendly.
|
1061
|
+
For example, these both compile by default to the same select tag:
|
1062
|
+
|
1063
|
+
f.input(:select, :options=>[['foo', 1]])
|
1064
|
+
# or
|
1065
|
+
f.tag(:select, {}, [f.tag(:option, {:value=>1}, ['foo'])])
|
1103
1066
|
|
1104
1067
|
The group of objects that perform the transformations to
|
1105
1068
|
the abstract syntax trees are known as transformers.
|
1106
1069
|
Transformers use a functional style, and all use a +call+-based
|
1107
1070
|
API, so you can use a +Proc+ for any custom transformer.
|
1071
|
+
The processing of high level <tt>Forme::Input</tt>s into raw HTML
|
1072
|
+
fragments is performed through the following transformers:
|
1073
|
+
|
1074
|
+
+Formatter+ :: converts a <tt>Forme::Input</tt> instance into a
|
1075
|
+
<tt>Forme::Tag</tt> instance (or array of them).
|
1076
|
+
+ErrorHandler+ :: If the <tt>Forme::Input</tt> instance has a error,
|
1077
|
+
takes the formatted tag and marks it as having the error.
|
1078
|
+
+Helper+ :: If the <tt>Forme::Input</tt> instance has any help text,
|
1079
|
+
adds the help text in a separate tag.
|
1080
|
+
+Labeler+ :: If the <tt>Forme::Input</tt> instance has a label,
|
1081
|
+
takes the formatted output and labels it.
|
1082
|
+
+Wrapper+ :: Takes the output of the formatter, labeler, and
|
1083
|
+
error_handler transformers, and wraps it in another tag (or just
|
1084
|
+
returns it unmodified).
|
1085
|
+
+Serializer+ :: converts a <tt>Forme::Tag</tt> instance into an
|
1086
|
+
HTML string.
|
1087
|
+
|
1088
|
+
Technically, only the +Serializer+ is necessary. The Forme::Form#input
|
1089
|
+
and Forme::Form#tag methods internally create +Input+ and
|
1090
|
+
+Tag+ objects. Before returning results, the input or tag is converted
|
1091
|
+
to a string using +to_s+, which calls the appropriate +Serializer+.
|
1092
|
+
The +Serializer+ calls the appropriate +Formatter+ if it encounters an
|
1093
|
+
+Input+ instance, and attempts to serialize the output of that (which is
|
1094
|
+
usually a +Tag+ instance). It is up to the +Formatter+ to call the +Labeler+,
|
1095
|
+
+ErrorHandler+, +Helper+, and/or +Wrapper+.
|
1096
|
+
|
1097
|
+
The Forme::Form object takes the transformers as options (:formatter,
|
1098
|
+
:labeler, :error_handler, :helper, :wrapper, and :serializer), all of which
|
1099
|
+
should be objects responding to +call+ (so you can use <tt>Proc</tt>s) or be symbols
|
1100
|
+
registered with the library using <tt>Forme.register_transformer</tt>:
|
1101
|
+
|
1102
|
+
Forme.register_transformer(:wrapper, :p) do |tag, input|
|
1103
|
+
input.tag(:p, {}, tag)
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
Most transformers are called with two arguments, +tag+ and +input+. +tag+
|
1107
|
+
is a <tt>Forme::Tag</tt> instance, and +input+ is a <tt>Forme::Input</tt>
|
1108
|
+
instance. The +Formatter+ and +Serializer+ transformers are the two
|
1109
|
+
exceptions, with +Formatter+ being called with just an +input+, and
|
1110
|
+
+Serializer+ potentionally being called with any object. The +Serializer+
|
1111
|
+
will in general recursively call itself with children of the argument
|
1112
|
+
given until a string is returned.
|
1113
|
+
|
1114
|
+
There is also an +InputsWrapper+ transformer, that is called by
|
1115
|
+
Forme::Form#inputs. It's used to wrap up a group of
|
1116
|
+
related options (in a +fieldset+ by default). It takes +form+
|
1117
|
+
(Forme::Form instance) and +input_opts+ (+Hash+) arguments.
|
1118
|
+
|
1119
|
+
Most of the transformers can be overridden on a per instance basis by
|
1120
|
+
passing the appropriate option to +input+ or +inputs+:
|
1121
|
+
|
1122
|
+
f.input(:name, :wrapper=>:p)
|
1123
|
+
|
1124
|
+
Existing transformers can be easily extended (ie, to set the class attribute),
|
1125
|
+
by creating your own transformer and then calling the existing transformer.
|
1126
|
+
|
1127
|
+
Forme.register_transformer(:labeler, :explicit) do |tag, input|
|
1128
|
+
input.opts[:label_attr] ||= { :class => 'label' }
|
1129
|
+
Forme::Labeler::Explicit.new.call(tag, input)
|
1130
|
+
end
|
1108
1131
|
|
1109
1132
|
== Transformer Types
|
1110
1133
|
|
1134
|
+
You can override the type of transform for each form or input using the
|
1135
|
+
following options:
|
1136
|
+
|
1111
1137
|
+serializer+ :: tags input/tag, returns string
|
1112
1138
|
+formatter+ :: takes input, returns tag
|
1113
1139
|
+error_handler+ :: takes tag and input, returns version of tag with errors noted
|
@@ -1240,7 +1266,7 @@ You can mark a configuration as the default using:
|
|
1240
1266
|
|
1241
1267
|
=== Bootstrap 3 Support
|
1242
1268
|
|
1243
|
-
Forme ships with support for Bootstrap 3 HTML formatting. This support is shipped in
|
1269
|
+
Forme ships with support for Bootstrap 3-4 HTML formatting. This support is shipped in
|
1244
1270
|
it's own file, so if you don't use it, you don't pay the memory penalty for loading
|
1245
1271
|
it.
|
1246
1272
|
|
@@ -1256,7 +1282,7 @@ All of these have external dependencies:
|
|
1256
1282
|
3. simple_form
|
1257
1283
|
4. padrino-helpers
|
1258
1284
|
|
1259
|
-
Forme's
|
1285
|
+
Forme's API draws a lot of inspiration from both Formtastic and simple_form.
|
1260
1286
|
|
1261
1287
|
= License
|
1262
1288
|
|