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