forme 2.4.1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 60794aa5c742e3b40bacd043172a0e201358b944a653f3bd013bf8e6a254154b
4
- data.tar.gz: ae16923653b5bb463f430735a57b1f710a3ccb53420b124f15b6a5e72f290c2e
3
+ metadata.gz: 79c0b3986af69becb74de866d9027eafb1af2b148056c60963e8c8c6af04ad3d
4
+ data.tar.gz: 8478ef6951317b7a33bf7c3b2630291bcd94bb94fcbb2820ef89d08c0addfaec
5
5
  SHA512:
6
- metadata.gz: b3f915c5dd32938874513739d29a2f6c04365a1f636c2dc814ce2a17de07beb4a9c8000e4f40b112bb8d4198d005552dafcf0cbb957dc0ffa9e11c0b6b820f33
7
- data.tar.gz: 5528741694ca0c36800ce9cacab5a7e764698da5c9c9f1e4bb17bfce9c9a0ba86a354a0e2eca14a9825b5ee792aa7dc5c62eb687b8d5a540fa7b2fea47220617
6
+ metadata.gz: c63cedc392288fba47d26da036ed2ad145acf4493683600cbad71238f66fd61dfeb91cadc1db68ab2211ff3cf6cd69622f17934f9ea0be4e4006a53c2baa0a07
7
+ data.tar.gz: ef4a1d7b5bfdd0dc83d5f52b87f8dbc0785f03ccdfdb8d7e1bdfe160e85636fc2165fae7916489c8d22ba082293a64b3e0a466c67e4a4fe3a90726f4d228ffb1
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ === 2.5.0 (2024-02-13)
2
+
3
+ * Add hidden inputs to work with formaction/formmethod support in Roda 3.77+ route_csrf plugin (jeremyevans)
4
+
5
+ * Support :formaction option on buttons (jeremyevans)
6
+
7
+ * Support emit: false option for non-rails template forms allowing block based form use without appending to template (jeremyevans)
8
+
1
9
  === 2.4.1 (2023-09-19)
2
10
 
3
11
  * Add dependency on bigdecimal, as bigdecimal is moving from standard library to bundled gem in Ruby 3.4 (jeremyevans)
data/README.rdoc CHANGED
@@ -800,7 +800,7 @@ For new code, it is recommended to use forme_route_csrf, as that uses Roda's rou
800
800
  plugin, which supports more secure request-specific CSRF tokens. In both cases, usage in ERB
801
801
  templates is the same:
802
802
 
803
- <% form(@obj, :action=>'/foo') do |f| %>
803
+ <% form(@obj, action: '/foo') do |f| %>
804
804
  <%= f.input(:field) %>
805
805
  <% f.tag(:fieldset) do %>
806
806
  <%= f.input(:field_two) %>
@@ -810,6 +810,8 @@ templates is the same:
810
810
  The forme_route_csrf plugin's +form+ method supports the following options
811
811
  in addition to the default +Forme.form+ options:
812
812
 
813
+ :emit :: Set to false to not emit implicit tags into template. This should only be
814
+ used if you are not modifying the template inside the block.
813
815
  :csrf :: Set to force whether a CSRF tag should be included. By default, a CSRF
814
816
  tag is included if the form's method is one of the request methods checked
815
817
  by the Roda route_csrf plugin.
@@ -818,6 +820,19 @@ in addition to the default +Forme.form+ options:
818
820
  CSRF token unless the Roda route_csrf plugin has been
819
821
  configured to support non-request specific tokens.
820
822
 
823
+ The <tt>emit: false</tt> option allows you to do:
824
+
825
+ <%= form(@obj, {action: '/foo'}, emit: false) do |f|
826
+ f.input(:field)
827
+ f.tag(:fieldset) do
828
+ f.input(:field_two)
829
+ end
830
+ end %>
831
+
832
+ This is useful if you are calling some method that calls +form+ with a block,
833
+ where the resulting entire Forme::Forme object will be literalized into the
834
+ template. The form will include the CSRF token and forme_set metadata as appropriate.
835
+
821
836
  The forme plugin does not require any csrf plugin, but will transparently use
822
837
  Rack::Csrf if it is available. If Rack::Csrf is available a CSRF tag if the form's
823
838
  method is +POST+, with no configuration ability.
@@ -856,7 +871,8 @@ It allows you to use the following API in your erb templates:
856
871
  <% end %>
857
872
 
858
873
  In order to this to work transparently, the ERB outvar needs to be <tt>@_out_buf</tt> (this is the
859
- default in Sinatra).
874
+ default in Sinatra). The Sinatra extension also supports the <tt>emit: false</tt> option to not
875
+ directly modify the related template (see example in the Roda section for usage).
860
876
 
861
877
  = Rails Support
862
878
 
@@ -72,9 +72,9 @@ module Forme
72
72
  private
73
73
 
74
74
  def _forme_form(obj, attr, opts, &block)
75
- if block_given?
75
+ if block && opts[:emit] != false
76
76
  erb_form = buffer = offset = nil
77
- block = proc do
77
+ form_block = proc do
78
78
  wrapped_form = erb_form.instance_variable_get(:@form)
79
79
  buffer = wrapped_form.to_s
80
80
  offset = buffer.length
@@ -83,9 +83,9 @@ module Forme
83
83
  offset = buffer.length
84
84
  end
85
85
 
86
- f, attr, block = _forme_wrapped_form_class.form_args(obj, attr, opts, &block)
86
+ f, attr, form_block = _forme_wrapped_form_class.form_args(obj, attr, opts, &form_block)
87
87
  erb_form = _forme_form_class.new(f, self)
88
- erb_form.form(attr, &block)
88
+ erb_form.form(attr, &form_block)
89
89
  erb_form.emit(buffer[offset, buffer.length])
90
90
  else
91
91
  _forme_wrapped_form_class.form(obj, attr, opts, &block)
@@ -268,6 +268,12 @@ module Forme
268
268
  ret
269
269
  end
270
270
 
271
+ # Formats a submit input. Respects :formaction option.
272
+ def format_submit
273
+ copy_options_to_attributes([:formaction])
274
+ _format_input(:submit)
275
+ end
276
+
271
277
  # Formats a textarea. Respects the following options:
272
278
  # :value :: Sets value as the child of the textarea.
273
279
  def format_textarea
data/lib/forme/version.rb CHANGED
@@ -6,11 +6,11 @@ module Forme
6
6
  MAJOR = 2
7
7
 
8
8
  # The minor version of Forme, updated for new feature releases of Forme.
9
- MINOR = 4
9
+ MINOR = 5
10
10
 
11
11
  # The patch version of Forme, updated only for bug fixes from the last
12
12
  # feature release.
13
- TINY = 1
13
+ TINY = 0
14
14
 
15
15
  # Version constant, use <tt>Forme.version</tt> instead.
16
16
  VERSION = "#{MAJOR}.#{MINOR}.#{TINY}".freeze
@@ -33,8 +33,8 @@ class Roda
33
33
  end
34
34
 
35
35
  module InstanceMethods
36
- def form(*)
37
- if block_given?
36
+ def _forme_form(obj, attr, opts, &block)
37
+ if block && opts[:emit] != false
38
38
  capture_erb do
39
39
  super
40
40
  instance_variable_get(render_opts[:template_opts][:outvar])
@@ -36,7 +36,7 @@ class Roda
36
36
  end
37
37
 
38
38
  if apply_csrf
39
- token = if opts.fetch(:use_request_specific_token){use_request_specific_csrf_tokens?}
39
+ token = if use_request_specific_token = opts.fetch(:use_request_specific_token){use_request_specific_csrf_tokens?}
40
40
  csrf_token(csrf_path(attr[:action]), method)
41
41
  else
42
42
  csrf_token
@@ -46,6 +46,23 @@ class Roda
46
46
  opts[:_before] = lambda do |form|
47
47
  form.tag(:input, :type=>:hidden, :name=>csrf_field, :value=>token)
48
48
  end
49
+
50
+ if use_request_specific_token && (formaction_field = csrf_options[:formaction_field])
51
+ formactions = opts[:formactions] = []
52
+ formaction_tokens = opts[:formaction_tokens] = {}
53
+ _after = opts[:_after]
54
+ opts[:formaction_csrfs] = [formaction_field, formaction_tokens]
55
+ formaction_field = csrf_options[:formaction_field]
56
+ opts[:_after] = lambda do |form|
57
+ formactions.each do |action, method|
58
+ path = csrf_path(action)
59
+ fa_token = csrf_token(path, method)
60
+ formaction_tokens[path] = fa_token
61
+ form.tag(:input, :type=>:hidden, :name=>"#{formaction_field}[#{path}]", :value=>fa_token)
62
+ end
63
+ _after.call(form) if _after
64
+ end
65
+ end
49
66
  end
50
67
  end
51
68
  end
@@ -102,7 +102,9 @@ class Roda
102
102
  def _forme_form_options(obj, attr, opts)
103
103
  super
104
104
 
105
+ _after = opts[:_after]
105
106
  opts[:_after] = lambda do |form|
107
+ _after.call(form) if _after
106
108
  if (obj = form.opts[:obj]) && obj.respond_to?(:forme_inputs) && (forme_inputs = obj.forme_inputs)
107
109
  columns = []
108
110
  valid_values = {}
@@ -129,6 +131,9 @@ class Roda
129
131
  data['columns'] = columns
130
132
  data['namespaces'] = form.opts[:namespace]
131
133
  data['csrf'] = form.opts[:csrf]
134
+ if (formactions = form.opts[:formaction_csrfs]) && !formactions[1].empty?
135
+ data['formaction_csrfs'] = formactions
136
+ end
132
137
  data['valid_values'] = valid_values unless valid_values.empty?
133
138
  data['form_version'] = form.opts[:form_version] if form.opts[:form_version]
134
139
 
@@ -154,8 +159,16 @@ class Roda
154
159
 
155
160
  data = JSON.parse(data)
156
161
  csrf_field, hmac_csrf_value = data['csrf']
162
+ formaction_csrf_field, formaction_values = data['formaction_csrfs']
163
+
157
164
  if csrf_field
158
- csrf_value = params[csrf_field].to_s
165
+ formaction_params = params[formaction_csrf_field]
166
+ if formaction_csrf_field && (formaction_params = params[formaction_csrf_field]).is_a?(Hash) && (csrf_value = formaction_params[request.path])
167
+ hmac_csrf_value = formaction_values[request.path]
168
+ else
169
+ csrf_value = params[csrf_field].to_s
170
+ end
171
+
159
172
  hmac_csrf_value = hmac_csrf_value.to_s
160
173
  unless Rack::Utils.secure_compare(csrf_value.ljust(hmac_csrf_value.length), hmac_csrf_value) && csrf_value.length == hmac_csrf_value.length
161
174
  return _forme_parse_error(:csrf_mismatch, obj)
@@ -17,6 +17,22 @@ module Sequel # :nodoc:
17
17
  # that use a <tt>Sequel::Model</tt> instance as the form's
18
18
  # +obj+.
19
19
  module SequelForm
20
+ # If the form has the :formactions option and the button has the
21
+ # formaction option or attribute, append the action and method
22
+ # for this button to the formactions. This is used by the
23
+ # Roda forme_route_csrf and forme_set plugins so that formaction
24
+ # can work as expected.
25
+ def button(opts={})
26
+ if opts.is_a?(Hash) && (formactions = self.opts[:formactions]) &&
27
+ (formaction = opts[:formaction] || ((attr = opts[:attr]) && (attr[:formaction] || attr['formaction'])))
28
+ formmethod = opts[:formmethod] ||
29
+ ((attr = opts[:attr]) && (attr[:formmethod] || attr['formmethod'])) ||
30
+ ((attr = form_tag_attributes) && (attr[:method] || attr['method']))
31
+ formactions << [formaction, formmethod]
32
+ end
33
+ super
34
+ end
35
+
20
36
  # Use the post method by default for Sequel forms, unless
21
37
  # overridden with the :method attribute.
22
38
  def form(attr={}, &block)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forme
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.1
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-19 00:00:00.000000000 Z
11
+ date: 2024-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal
@@ -239,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
239
239
  - !ruby/object:Gem::Version
240
240
  version: '0'
241
241
  requirements: []
242
- rubygems_version: 3.4.10
242
+ rubygems_version: 3.5.3
243
243
  signing_key:
244
244
  specification_version: 4
245
245
  summary: HTML forms library