module Roda::RodaPlugins::FormeSet::InstanceMethods

Public Instance Methods

form(obj=nil, attr={}, opts={}, &block) click to toggle source

If a Sequel::Model object that supports forme_set is passed, isolate the inputs so that each form only includes metadata for inputs on the form, and not inputs for earlier forms on the same page.

Calls superclass method
   # File lib/roda/plugins/forme_set.rb
44 def form(obj=nil, attr={}, opts={}, &block)
45   if obj.is_a?(Sequel::Plugins::FormeSet::InstanceMethods)
46     obj.isolate_forme_inputs{super}
47   else
48     super
49   end
50 end
forme_parse(obj) click to toggle source

Return hash based on submitted parameters, with :values key being submitted values for the object, and :validations key being a hash of validation metadata for the object.

   # File lib/roda/plugins/forme_set.rb
55 def forme_parse(obj)
56   h = _forme_parse(obj)
57   
58   params = h.delete(:params)
59   columns = h.delete(:columns)
60   h[:validations] ||= {}
61 
62   values = h[:values] = {}
63   columns.each do |col|
64     values[col.to_sym] = params[col]
65   end
66 
67   h
68 end
forme_set(obj) { |h, obj| ... } click to toggle source

Set fields on the object based on submitted parameters, as well as validations for associated object values.

   # File lib/roda/plugins/forme_set.rb
72 def forme_set(obj)
73   h = _forme_parse(obj)
74 
75   obj.set_fields(h[:params], h[:columns])
76 
77   if h[:validations]
78     obj.forme_validations.merge!(h[:validations])
79   end
80 
81   if block_given?
82     yield h[:form_version], obj
83   end
84 
85   obj
86 end

Private Instance Methods

_forme_form_options(obj, attr, opts) click to toggle source

Include a reference to the current scope to the form. This reference is needed to correctly construct the HMAC.

Calls superclass method
    # File lib/roda/plugins/forme_set.rb
102 def _forme_form_options(obj, attr, opts)
103   super
104 
105   _after = opts[:_after]
106   opts[:_after] = lambda do |form|
107     _after.call(form) if _after
108     if (obj = form.opts[:obj]) && obj.respond_to?(:forme_inputs) && (forme_inputs = obj.forme_inputs)
109       columns = []
110       valid_values = {}
111 
112       forme_inputs.each do |field, input|
113         next unless col = obj.send(:forme_column_for_input, input)
114         col = col.to_s
115         columns << col
116 
117         next unless validation = obj.send(:forme_validation_for_input, field, input)
118         validation[0] = validation[0].to_s
119         has_nil = false
120         validation[1] = validation[1].map do |v|
121           has_nil ||= v.nil?
122           v.to_s
123         end
124         validation[1] << nil if has_nil
125         valid_values[col] = validation
126       end
127 
128       return if columns.empty?
129 
130       data = {}
131       data['columns'] = columns
132       data['namespaces'] = form.opts[:namespace]
133       data['csrf'] = form.opts[:csrf]
134       if (formactions = form.opts[:formaction_csrfs]) && !formactions[1].empty?
135         data['formaction_csrfs'] = formactions
136       end
137       data['valid_values'] = valid_values unless valid_values.empty?
138       data['form_version'] = form.opts[:form_version] if form.opts[:form_version]
139 
140       data = data.to_json
141       form.tag(:input, :type=>:hidden, :name=>:_forme_set_data, :value=>data)
142       form.tag(:input, :type=>:hidden, :name=>:_forme_set_data_hmac, :value=>OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, self.class.opts[:forme_set_hmac_secret], data))
143     end
144   end
145 end
_forme_parse(obj) click to toggle source

Internals of forme_parse_hmac and forme_set_hmac.

    # File lib/roda/plugins/forme_set.rb
148 def _forme_parse(obj)
149   params = request.params
150   return _forme_parse_error(:missing_data, obj) unless data = params['_forme_set_data']
151   return _forme_parse_error(:missing_hmac, obj) unless hmac = params['_forme_set_data_hmac']
152 
153   data = data.to_s
154   hmac = hmac.to_s
155   actual = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, self.class.opts[:forme_set_hmac_secret], data)
156   unless Rack::Utils.secure_compare(hmac.ljust(64), actual) && hmac.length == actual.length
157     return _forme_parse_error(:hmac_mismatch, obj)
158   end
159 
160   data = JSON.parse(data)
161   csrf_field, hmac_csrf_value = data['csrf']
162   formaction_csrf_field, formaction_values = data['formaction_csrfs']
163 
164   if csrf_field
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 
172     hmac_csrf_value = hmac_csrf_value.to_s
173     unless Rack::Utils.secure_compare(csrf_value.ljust(hmac_csrf_value.length), hmac_csrf_value) && csrf_value.length == hmac_csrf_value.length
174       return _forme_parse_error(:csrf_mismatch, obj)
175     end
176   end
177 
178   namespaces = data['namespaces']
179   namespaces.each do |key|
180     return _forme_parse_error(:missing_namespace, obj) unless params = params[key]
181   end
182 
183   if valid_values = data['valid_values']
184     validations = {}
185     valid_values.each do |col, (type, values)|
186       value = params[col]
187       valid = if type == "subset"
188         !value || (value - values).empty?
189       else # type == "include"
190         values.include?(value)
191       end
192 
193       validations[col.to_sym] = [:valid, valid]
194     end
195   end
196 
197   {:params=>params, :columns=>data["columns"], :validations=>validations, :form_version=>data['form_version']}
198 end
_forme_parse_error(type, obj) click to toggle source

Raise error with message based on type

   # File lib/roda/plugins/forme_set.rb
95 def _forme_parse_error(type, obj)
96   _forme_set_handle_error(type, obj)
97   raise Error, ERROR_MESSAGES[type]
98 end
_forme_set_handle_error(type, _obj) click to toggle source

Raise error with message based on type

   # File lib/roda/plugins/forme_set.rb
91 def _forme_set_handle_error(type, _obj)
92 end