bureaucrat 0.0.3 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +120 -105
- data/Rakefile +9 -0
- data/bureaucrat.gemspec +32 -0
- data/lib/bureaucrat.rb +26 -8
- data/lib/bureaucrat/fields.rb +572 -336
- data/lib/bureaucrat/forms.rb +296 -257
- data/lib/bureaucrat/formsets.rb +235 -194
- data/lib/bureaucrat/quickfields.rb +90 -62
- data/lib/bureaucrat/temporary_uploaded_file.rb +14 -0
- data/lib/bureaucrat/utils.rb +79 -62
- data/lib/bureaucrat/validators.rb +163 -0
- data/lib/bureaucrat/widgets.rb +459 -303
- data/test/fields_test.rb +519 -380
- data/test/forms_test.rb +78 -58
- data/test/formsets_test.rb +48 -22
- data/test/test_helper.rb +20 -12
- data/test/widgets_test.rb +224 -204
- metadata +27 -36
- data/lib/bureaucrat/validation.rb +0 -130
- data/lib/bureaucrat/validation_old.rb +0 -148
- data/lib/bureaucrat/wizard.rb +0 -220
data/lib/bureaucrat/forms.rb
CHANGED
@@ -1,199 +1,284 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
1
|
+
module Bureaucrat
|
2
|
+
module Forms
|
3
|
+
|
4
|
+
# Instances of +BoundField+ represent a fields with associated data.
|
5
|
+
# +BoundField+s are used internally by the +Form+ class.
|
6
|
+
class BoundField
|
7
|
+
include Utils
|
8
|
+
|
9
|
+
# Field label text
|
10
|
+
attr_accessor :label, :form, :field, :name, :html_name, :html_initial_name, :help_text
|
11
|
+
|
12
|
+
# Instantiates a new +BoundField+ associated to +form+'s field +field+
|
13
|
+
# named +name+.
|
14
|
+
def initialize(form, field, name)
|
15
|
+
@form = form
|
16
|
+
@field = field
|
17
|
+
@name = name
|
18
|
+
@html_name = form.add_prefix(name)
|
19
|
+
@html_initial_name = form.add_initial_prefix(name)
|
20
|
+
@label = @field.label || pretty_name(name)
|
21
|
+
@help_text = @field.help_text || ''
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
# Renders the field.
|
25
|
+
def to_s
|
26
|
+
@field.show_hidden_initial ? as_widget + as_hidden(nil, true) : as_widget
|
27
|
+
end
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
# Errors for this field.
|
30
|
+
def errors
|
31
|
+
@form.errors.fetch(@name, @form.error_class.new)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Renders this field with the option of using alternate widgets
|
35
|
+
# and attributes.
|
36
|
+
def as_widget(widget=nil, attrs=nil, only_initial=false)
|
37
|
+
widget ||= @field.widget
|
38
|
+
attrs ||= {}
|
39
|
+
auto_id = self.auto_id
|
40
|
+
attrs[:id] ||= auto_id if auto_id && !widget.attrs.key?(:id)
|
29
41
|
|
30
|
-
|
31
|
-
widget ||= @field.widget
|
32
|
-
attrs ||= {}
|
33
|
-
auto_id = self.auto_id
|
34
|
-
attrs[:id] ||= auto_id if auto_id && !widget.attrs.key?(:id)
|
35
|
-
|
36
|
-
if !@form.bound?
|
37
|
-
data = @form.initial.fetch(@name.to_s, @field.initial)
|
38
|
-
data = data.call if data.respond_to?(:call)
|
39
|
-
else
|
40
|
-
if @field.is_a?(Fields::FileField) && @data.nil?
|
42
|
+
if !@form.bound?
|
41
43
|
data = @form.initial.fetch(@name, @field.initial)
|
44
|
+
data = data.call if data.respond_to?(:call)
|
42
45
|
else
|
43
|
-
|
46
|
+
if @field.is_a?(Fields::FileField) && @data.nil?
|
47
|
+
data = @form.initial.fetch(@name, @field.initial)
|
48
|
+
else
|
49
|
+
data = self.data
|
50
|
+
end
|
44
51
|
end
|
52
|
+
|
53
|
+
name = only_initial ? @html_initial_name : @html_name
|
54
|
+
widget.render(name.to_s, data, attrs)
|
45
55
|
end
|
46
56
|
|
47
|
-
|
57
|
+
# Renders this field as a text input.
|
58
|
+
def as_text(attrs=nil, only_initial=false)
|
59
|
+
as_widget(Widgets::TextInput.new, attrs, only_initial)
|
60
|
+
end
|
48
61
|
|
49
|
-
|
50
|
-
|
62
|
+
# Renders this field as a text area.
|
63
|
+
def as_textarea(attrs=nil, only_initial=false)
|
64
|
+
as_widget(Widgets::Textarea.new, attrs, only_initial)
|
65
|
+
end
|
51
66
|
|
52
|
-
|
53
|
-
|
54
|
-
|
67
|
+
# Renders this field as hidden.
|
68
|
+
def as_hidden(attrs=nil, only_initial=false)
|
69
|
+
as_widget(@field.hidden_widget, attrs, only_initial)
|
70
|
+
end
|
55
71
|
|
56
|
-
|
57
|
-
|
58
|
-
|
72
|
+
# The data associated to this field.
|
73
|
+
def data
|
74
|
+
@field.widget.value_from_formdata(@form.data, @html_name)
|
75
|
+
end
|
59
76
|
|
60
|
-
|
61
|
-
|
62
|
-
|
77
|
+
def value
|
78
|
+
# Returns the value for this BoundField, using the initial value if
|
79
|
+
# the form is not bound or the data otherwise.
|
63
80
|
|
64
|
-
|
65
|
-
|
66
|
-
|
81
|
+
if form.bound?
|
82
|
+
val = field.bound_data(data, form.initial.fetch(name, field.initial))
|
83
|
+
else
|
84
|
+
val = form.initial.fetch(name, field.initial)
|
85
|
+
if val.respond_to?(:call)
|
86
|
+
val = val.call
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
field.prepare_value(val)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Renders the label tag for this field.
|
94
|
+
def label_tag(contents=nil, attrs=nil)
|
95
|
+
contents ||= conditional_escape(@label)
|
96
|
+
widget = @field.widget
|
97
|
+
id_ = widget.attrs[:id] || self.auto_id
|
67
98
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
99
|
+
if id_
|
100
|
+
attrs = attrs ? flatatt(attrs) : ''
|
101
|
+
contents = "<label for=\"#{Widgets::Widget.id_for_label(id_)}\"#{attrs}>#{contents}</label>"
|
102
|
+
end
|
72
103
|
|
73
|
-
|
74
|
-
attrs = attrs ? flattatt(attrs) : ''
|
75
|
-
contents = "<label for=\"#{Widgets::Widget.id_for_label(id_)}\"#{attrs}>#{contents}</label>"
|
104
|
+
mark_safe(contents)
|
76
105
|
end
|
77
106
|
|
78
|
-
|
79
|
-
|
107
|
+
def css_classes(extra_classes = nil)
|
108
|
+
# Returns a string of space-separated CSS classes for this field.
|
80
109
|
|
81
|
-
|
82
|
-
|
83
|
-
|
110
|
+
if extra_classes.respond_to?(:split)
|
111
|
+
extra_classes = extra_classes.split
|
112
|
+
end
|
84
113
|
|
85
|
-
|
86
|
-
fauto_id = @form.auto_id
|
87
|
-
fauto_id ? fauto_id % @html_name : ''
|
88
|
-
end
|
89
|
-
end
|
114
|
+
extra_classes = Set.new(extra_classes)
|
90
115
|
|
91
|
-
|
92
|
-
|
93
|
-
|
116
|
+
if !errors.empty? && !Utils.blank_value?(form.error_css_class)
|
117
|
+
extra_classes << form.error_css_class
|
118
|
+
end
|
94
119
|
|
95
|
-
|
96
|
-
|
120
|
+
if field.required && !Utils.blank_value?(form.required_css_class)
|
121
|
+
extra_classes << form.required_css_class
|
122
|
+
end
|
97
123
|
|
98
|
-
|
99
|
-
@base_fields ||= Utils::OrderedHash.new
|
124
|
+
extra_classes.to_a.join(' ')
|
100
125
|
end
|
101
126
|
|
102
|
-
|
103
|
-
|
127
|
+
# true if the widget for this field is of the hidden kind.
|
128
|
+
def hidden?
|
129
|
+
@field.widget.hidden?
|
104
130
|
end
|
105
131
|
|
106
|
-
#
|
107
|
-
def
|
108
|
-
|
109
|
-
|
132
|
+
# Generates the id for this field.
|
133
|
+
def auto_id
|
134
|
+
fauto_id = @form.auto_id
|
135
|
+
fauto_id ? fauto_id % @html_name : ''
|
110
136
|
end
|
111
137
|
end
|
112
138
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
@files = options.fetch(:files, {})
|
122
|
-
@auto_id = options.fetch(:auto_id, 'id_%s')
|
123
|
-
@prefix = options[:prefix]
|
124
|
-
@initial = options.fetch(:initial, {})
|
125
|
-
@error_class = options.fetch(:error_class, Fields::ErrorList)
|
126
|
-
@label_suffix = options.fetch(:label_suffix, ':')
|
127
|
-
@empty_permitted = options.fetch(:empty_permitted, false)
|
128
|
-
@errors = nil
|
129
|
-
@changed_data = nil
|
130
|
-
|
131
|
-
@fields = self.class.base_fields.dup
|
132
|
-
@fields.each { |key, value| @fields[key] = value.dup }
|
133
|
-
end
|
139
|
+
# Base class for forms. Forms are a collection of fields with data that
|
140
|
+
# knows how to render and validate itself.
|
141
|
+
#
|
142
|
+
# === Bound vs Unbound forms
|
143
|
+
# A form is 'bound' if it was initialized with a set of data for its fields,
|
144
|
+
# otherwise it is 'unbound'. Only bound forms can be validated. Unbound
|
145
|
+
# forms always respond with false to +valid?+ and return an empty
|
146
|
+
# list of errors.
|
134
147
|
|
135
|
-
|
136
|
-
|
137
|
-
end
|
148
|
+
class Form
|
149
|
+
include Utils
|
138
150
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
151
|
+
# Fields associated to the form class
|
152
|
+
def self.base_fields
|
153
|
+
@base_fields ||= {}
|
154
|
+
end
|
143
155
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
156
|
+
# Declares a named field to be used on this form.
|
157
|
+
def self.field(name, field_obj)
|
158
|
+
base_fields[name] = field_obj
|
159
|
+
end
|
148
160
|
|
149
|
-
|
150
|
-
|
151
|
-
|
161
|
+
# Copy data to the child class
|
162
|
+
def self.inherited(c)
|
163
|
+
super(c)
|
164
|
+
c.instance_variable_set(:@base_fields, base_fields.dup)
|
165
|
+
end
|
152
166
|
|
153
|
-
|
154
|
-
|
155
|
-
|
167
|
+
# Error object class for this form
|
168
|
+
attr_accessor :error_class
|
169
|
+
# Required class for this form
|
170
|
+
attr_accessor :required_css_class
|
171
|
+
# Required class for this form
|
172
|
+
attr_accessor :error_css_class
|
173
|
+
# Format string for field id generator
|
174
|
+
attr_accessor :auto_id
|
175
|
+
# Hash of {field_name => initial_value}
|
176
|
+
attr_accessor :initial
|
177
|
+
# Data associated to this form {field_name => value}
|
178
|
+
attr_accessor :data
|
179
|
+
# TODO: complete implementation
|
180
|
+
attr_accessor :files
|
181
|
+
# Validated and cleaned data
|
182
|
+
attr_accessor :cleaned_data
|
183
|
+
# Fields belonging to this form
|
184
|
+
attr_accessor :fields
|
185
|
+
|
186
|
+
# Checks if this form was initialized with data.
|
187
|
+
def bound? ; @is_bound; end
|
188
|
+
|
189
|
+
# Instantiates a new form bound to the passed data (or unbound if data is nil)
|
190
|
+
#
|
191
|
+
# +data+ is a hash of {field_name => value} for this form to be bound
|
192
|
+
# (will be unbound if nil)
|
193
|
+
#
|
194
|
+
# Possible options are:
|
195
|
+
# :prefix prefix that will be used for fields when rendered
|
196
|
+
# :auto_id format string that will be used when generating
|
197
|
+
# field ids (default: 'id_%s')
|
198
|
+
# :initial hash of {field_name => default_value}
|
199
|
+
# (doesn't make a form bound)
|
200
|
+
# :error_class class used to represent errors (default: ErrorList)
|
201
|
+
# :label_suffix suffix string that will be appended to labels' text
|
202
|
+
# (default: ':')
|
203
|
+
# :empty_permitted boolean value that specifies if this form is valid
|
204
|
+
# when empty
|
205
|
+
|
206
|
+
def initialize(data=nil, options={})
|
207
|
+
@is_bound = !data.nil?
|
208
|
+
@data = StringAccessHash.new(data || {})
|
209
|
+
@files = options.fetch(:files, {})
|
210
|
+
@auto_id = options.fetch(:auto_id, 'id_%s')
|
211
|
+
@prefix = options[:prefix]
|
212
|
+
@initial = StringAccessHash.new(options.fetch(:initial, {}))
|
213
|
+
@error_class = options.fetch(:error_class, Fields::ErrorList)
|
214
|
+
@label_suffix = options.fetch(:label_suffix, ':')
|
215
|
+
@empty_permitted = options.fetch(:empty_permitted, false)
|
216
|
+
@errors = nil
|
217
|
+
@changed_data = nil
|
218
|
+
|
219
|
+
@fields = self.class.base_fields.dup
|
220
|
+
@fields.each { |key, value| @fields[key] = value.dup }
|
221
|
+
end
|
156
222
|
|
157
|
-
|
158
|
-
|
159
|
-
|
223
|
+
# Iterates over the fields
|
224
|
+
def each
|
225
|
+
@fields.each do |name, field|
|
226
|
+
yield BoundField.new(self, field, name)
|
227
|
+
end
|
228
|
+
end
|
160
229
|
|
161
|
-
|
162
|
-
|
163
|
-
|
230
|
+
# Access a named field
|
231
|
+
def [](name)
|
232
|
+
field = @fields[name] or return nil
|
233
|
+
BoundField.new(self, field, name)
|
234
|
+
end
|
164
235
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
236
|
+
# Errors for this forms (runs validations)
|
237
|
+
def errors
|
238
|
+
full_clean if @errors.nil?
|
239
|
+
@errors
|
240
|
+
end
|
170
241
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
242
|
+
# Perform validation and returns true if there are no errors
|
243
|
+
def valid?
|
244
|
+
@is_bound && (errors.nil? || errors.empty?)
|
245
|
+
end
|
175
246
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
247
|
+
# Generates a prefix for field named +field_name+
|
248
|
+
def add_prefix(field_name)
|
249
|
+
@prefix ? "#{@prefix}-#{field_name}" : field_name
|
250
|
+
end
|
180
251
|
|
181
|
-
|
182
|
-
|
183
|
-
|
252
|
+
# Generates an initial-prefix for field named +field_name+
|
253
|
+
def add_initial_prefix(field_name)
|
254
|
+
"initial-#{add_prefix(field_name)}"
|
255
|
+
end
|
256
|
+
|
257
|
+
# true if the form is valid when empty
|
258
|
+
def empty_permitted?
|
259
|
+
@empty_permitted
|
260
|
+
end
|
184
261
|
|
185
|
-
|
186
|
-
|
262
|
+
# Returns the list of errors that aren't associated to a specific field
|
263
|
+
def non_field_errors
|
264
|
+
errors.fetch(:__NON_FIELD_ERRORS, @error_class.new)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Runs all the validations for this form. If the form is invalid
|
268
|
+
# the list of errors is populated, if it is valid, cleaned_data is
|
269
|
+
# populated
|
270
|
+
def full_clean
|
271
|
+
@errors = Fields::ErrorHash.new
|
187
272
|
|
188
|
-
|
273
|
+
return unless bound?
|
189
274
|
|
190
|
-
|
275
|
+
@cleaned_data = StringAccessHash.new
|
191
276
|
|
192
|
-
|
277
|
+
return if empty_permitted? && !changed?
|
193
278
|
|
194
|
-
|
195
|
-
value = field.widget.
|
196
|
-
|
279
|
+
@fields.each do |name, field|
|
280
|
+
value = field.widget.
|
281
|
+
value_from_formdata(@data, add_prefix(name))
|
197
282
|
|
198
283
|
begin
|
199
284
|
if field.is_a?(Fields::FileField)
|
@@ -205,142 +290,96 @@ module Bureaucrat; module Forms
|
|
205
290
|
|
206
291
|
clean_method = 'clean_%s' % name
|
207
292
|
@cleaned_data[name] = send(clean_method) if respond_to?(clean_method)
|
208
|
-
rescue
|
293
|
+
rescue ValidationError => e
|
209
294
|
@errors[name] = e.messages
|
210
|
-
@cleaned_data.
|
295
|
+
@cleaned_data.delete(name)
|
211
296
|
end
|
212
297
|
end
|
213
298
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
299
|
+
begin
|
300
|
+
@cleaned_data = clean
|
301
|
+
rescue ValidationError => e
|
302
|
+
@errors[:__NON_FIELD_ERRORS] = e.messages
|
303
|
+
end
|
304
|
+
@cleaned_data = nil if @errors && !@errors.empty?
|
218
305
|
end
|
219
|
-
@cleaned_data = nil if @errors && !@errors.empty?
|
220
|
-
end
|
221
306
|
|
222
|
-
|
223
|
-
|
224
|
-
|
307
|
+
# Performs the last step of validations on the form, override in subclasses
|
308
|
+
# to customize behaviour.
|
309
|
+
def clean
|
310
|
+
@cleaned_data
|
311
|
+
end
|
225
312
|
|
226
|
-
|
227
|
-
|
228
|
-
|
313
|
+
# true if the form has data that isn't equal to its initial data
|
314
|
+
def changed?
|
315
|
+
changed_data && !changed_data.empty?
|
316
|
+
end
|
229
317
|
|
230
|
-
|
231
|
-
|
232
|
-
@changed_data
|
318
|
+
# List names for fields that have changed data
|
319
|
+
def changed_data
|
320
|
+
if @changed_data.nil?
|
321
|
+
@changed_data = []
|
233
322
|
|
234
|
-
|
323
|
+
@fields.each do |name, field|
|
235
324
|
prefixed_name = add_prefix(name)
|
236
|
-
data_value = field.widget.
|
237
|
-
|
325
|
+
data_value = field.widget.
|
326
|
+
value_from_formdata(@data, prefixed_name)
|
327
|
+
|
238
328
|
if !field.show_hidden_initial
|
239
329
|
initial_value = @initial.fetch(name, field.initial)
|
240
330
|
else
|
241
331
|
initial_prefixed_name = add_initial_prefix(name)
|
242
332
|
hidden_widget = field.hidden_widget.new
|
243
|
-
initial_value = hidden_widget.
|
244
|
-
|
333
|
+
initial_value = hidden_widget.
|
334
|
+
value_from_formdata(@data, initial_prefixed_name)
|
245
335
|
end
|
246
336
|
|
247
337
|
@changed_data << name if
|
248
338
|
field.widget.has_changed?(initial_value, data_value)
|
249
339
|
end
|
250
|
-
end
|
251
|
-
|
252
|
-
@changed_data
|
253
|
-
end
|
254
|
-
|
255
|
-
def media
|
256
|
-
@fields.values.inject(Widgets::Media.new) do |media, field|
|
257
|
-
media + field.widget.media
|
258
340
|
end
|
259
|
-
end
|
260
|
-
|
261
|
-
def multipart?
|
262
|
-
@fields.any? {|f| f.widgetneeds_multipart_form?}
|
263
|
-
end
|
264
|
-
|
265
|
-
def hidden_fields
|
266
|
-
@fields.select {|f| f.hidden?}
|
267
|
-
end
|
268
341
|
|
269
|
-
|
270
|
-
|
271
|
-
end
|
342
|
+
@changed_data
|
343
|
+
end
|
272
344
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
345
|
+
# true if this form contains fields that require the form to be
|
346
|
+
# multipart
|
347
|
+
def multipart?
|
348
|
+
@fields.any? {|f| f.widget.multipart_form?}
|
349
|
+
end
|
278
350
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
351
|
+
# List of hidden fields.
|
352
|
+
def hidden_fields
|
353
|
+
@fields.select {|f| f.hidden?}
|
354
|
+
end
|
283
355
|
|
284
|
-
|
285
|
-
|
356
|
+
# List of visible fields
|
357
|
+
def visible_fields
|
358
|
+
@fields.select {|f| !f.hidden?}
|
359
|
+
end
|
286
360
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
bf = BoundField.new(self, field, name)
|
292
|
-
bf_errors = @error_class.new(bf.errors.map {|e| conditional_escape(e)})
|
293
|
-
if bf.hidden?
|
294
|
-
top_errors += bf_errors.map do |e|
|
295
|
-
"(Hidden field #{name}) #{e.to_s}"
|
296
|
-
end unless bf_errors.empty?
|
297
|
-
hidden_fields << bf.to_s
|
298
|
-
else
|
299
|
-
output << error_row % bf_errors if
|
300
|
-
errors_on_separate_row && !bf_errors.empty?
|
301
|
-
|
302
|
-
label = ''
|
303
|
-
unless bf.label.nil? || bf.label.empty?
|
304
|
-
label = conditional_escape(bf.label)
|
305
|
-
label += @label_suffix if @label_suffix && label[-1,1] !~ /[:?.!]/
|
306
|
-
label = bf.label_tag(label)
|
307
|
-
end
|
361
|
+
# Attributes for labels, override in subclasses to customize behaviour
|
362
|
+
def label_attributes(name, field)
|
363
|
+
{}
|
364
|
+
end
|
308
365
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
}
|
314
|
-
output << format_string(normal_row, vars)
|
315
|
-
end
|
366
|
+
# Populates the passed object's attributes with data from the fields
|
367
|
+
def populate_object(object)
|
368
|
+
@fields.each do |name, field|
|
369
|
+
field.populate_object(object, name, @cleaned_data[name])
|
316
370
|
end
|
317
|
-
|
371
|
+
end
|
318
372
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
:errors => '', :label => '', :field => '', :help_text => ''
|
328
|
-
}
|
329
|
-
last_row = format_string(normal_row, vars)
|
330
|
-
output << last_row
|
331
|
-
end
|
332
|
-
output[-1] = last_row[0...-row_ender.length] + str_hidden + row_ender
|
333
|
-
else
|
334
|
-
output << str_hidden
|
335
|
-
end
|
373
|
+
private
|
374
|
+
|
375
|
+
# Returns the value for the field name +field_name+ from the associated
|
376
|
+
# data
|
377
|
+
def raw_value(fieldname)
|
378
|
+
field = @fields.fetch(fieldname)
|
379
|
+
prefix = add_prefix(fieldname)
|
380
|
+
field.widget.value_from_formdata(@data, prefix)
|
336
381
|
end
|
337
|
-
end
|
338
382
|
|
339
|
-
def raw_value(fieldname)
|
340
|
-
field = @fields.fetch(fieldname)
|
341
|
-
prefix = add_prefix(fieldname)
|
342
|
-
field.widget.value_from_datahash(@data, @files, prefix)
|
343
383
|
end
|
344
|
-
|
345
384
|
end
|
346
|
-
end
|
385
|
+
end
|