Class: Bureaucrat::FormWizard

Inherits:
Object
  • Object
show all
Defined in:
lib/bureaucrat/wizard.rb

Class Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(form_list, initial = Hash.new) ⇒ FormWizard

Returns a new instance of FormWizard.



45
46
47
48
49
# File 'lib/bureaucrat/wizard.rb', line 45

def initialize(form_list, initial=Hash.new)
  @form_list = form_list.dup
  @initial = initial
  @step = 0
end

Class Attribute Details

.step_field_nameObject

Returns the value of attribute step_field_name.



40
41
42
# File 'lib/bureaucrat/wizard.rb', line 40

def step_field_name
  @step_field_name
end

Instance Method Details

#determine_step(request, *args) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
# File 'lib/bureaucrat/wizard.rb', line 149

def determine_step(request, *args)
  if request.post?
    begin
      Integer(request.POST.fetch(step_field_name, 0))
    rescue ArgumentError
      0
    end
  else
    0
  end
end

#done(request, form_list) ⇒ Object

METHODS SUBCLASSES MUST OVERRIDE ########################################

Raises:

  • (NotImplementedError)


216
217
218
# File 'lib/bureaucrat/wizard.rb', line 216

def done(request, form_list)
  raise NotImplementedError.new("#{self.class.name} doesn't define the required 'done' method.")
end

#get_form(step, data = nil) ⇒ Object



51
52
53
54
55
# File 'lib/bureaucrat/wizard.rb', line 51

def get_form(step, data=nil)
  @form_list[step].new(data,
                       :prefix => prefix_for_step(step),
                       :initial => @initial.fetch(step, nil))
end

#get_template(step) ⇒ Object



164
165
166
# File 'lib/bureaucrat/wizard.rb', line 164

def get_template(step)
  'forms/wizard.erb'
end

#new(request, *args) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/bureaucrat/wizard.rb', line 61

def new(request, *args)
  current_step = determine_step(request, *args)
  parse_params(request, *args)

  raise ArgumentError("Step #{current_step} does not exist") if
    current_step >= num_steps

  (0...current_step).each do |i|
    form = get_form(i, request.POST)

    return render_hash_failure(request, i) if
      request.POST.fetch("hash_#{i}", '') != security_hash(request, form)

    process_step(request, form, i)
  end

  form = get_form(current_step, request.post? ? request.POST : nil)

  if form.valid?
    process_step(request, form, current_step)
    next_step = current_step + 1

    if next_step == num_steps
      final_form_list = (0...num_steps).map {|i| get_form(i, request.POST)}

      final_form_list.each_with_index do |f, i|
        return render_revalidation_failure(request, i, f) unless f.valid?
      end

      return done(request, final_form_list)
    else
      form = get_form(next_step)
      @step = current_step = next_step
    end
  end

  render(form, request, current_step)
end

#num_stepsObject



57
58
59
# File 'lib/bureaucrat/wizard.rb', line 57

def num_steps
  @form_list.length
end

#parse_params(request, *args) ⇒ Object



161
162
# File 'lib/bureaucrat/wizard.rb', line 161

def parse_params(request, *args)
end

#prefix_for_step(step) ⇒ Object

METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE



122
123
124
# File 'lib/bureaucrat/wizard.rb', line 122

def prefix_for_step(step)
  step.to_s
end

#process_step(request, form, step) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/bureaucrat/wizard.rb', line 201

def process_step(request, form, step)
  # Hook for modifying the FormWizard's internal state, given a fully
  # validated Form object. The Form is guaranteed to have clean, valid
  # data.

  # This method should *not* modify any of that data. Rather, it might want
  # to set self.extra_context or dynamically alter self.form_list, based on
  # previously submitted forms.

  # Note that this method is called every time a page is rendered for *all*
  # submitted steps.
end

#render(form, request, step, context = nil) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/bureaucrat/wizard.rb', line 100

def render(form, request, step, context=nil)
  "Renders the given Form object, returning an HttpResponse." # FIXME
  old_data = request.POST
  prev_fields = []

  if old_data
    hidden = Widgets::HiddenInput.new
    # Collect all data from previous steps and render it as HTML hidden fields.
    (0...step).each do |i|
      old_form = get_form(i, old_data)
      hash_name = "hash_#{i}"
      hash = old_data[hash_name] || security_hash(request, old_form)
      prev_fields += old_form.map {|bf| bf.as_hidden}
      prev_fields << hidden.render(hash_name, hash)
    end
  end

  render_template(request, form, prev_fields.join(''), step, context)
end

#render_hash_failure(request, step) ⇒ Object



126
127
128
129
130
131
132
133
134
135
# File 'lib/bureaucrat/wizard.rb', line 126

def render_hash_failure(request, step)
  # Hook for rendering a template if a hash check failed.

  # step is the step that failed. Any previous step is guaranteed to be
  # valid.

  # This default implementation simply renders the form for the given step,
  # but subclasses may want to display an error message, etc.
  render(get_form(step), request, step, :context => {:wizard_error => _('We apologize, but your form has expired. Please continue filling out the form from this page.')})
end

#render_revalidation_failure(request, step, form) ⇒ Object



137
138
139
140
141
142
143
# File 'lib/bureaucrat/wizard.rb', line 137

def render_revalidation_failure(request, step, form)
  # Hook for rendering a template if final revalidation failed.

  # It is highly unlikely that this point would ever be reached, but See
  # the comment in __call__() for an explanation.
  render(form, request, step)
end

#render_template(request, form, previous_fields, step, context = nil) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/bureaucrat/wizard.rb', line 168

def render_template(request, form, previous_fields, step, context=nil)

  # Renders the template for the given step, returning an HttpResponse object.

  # Override this method if you want to add a custom context, return a
  # different MIME type, etc. If you only need to override the template
  # name, use get_template() instead.

  # The template will be rendered with the following context:
  #     step_field -- The name of the hidden field containing the step.
  #     step0      -- The current step (zero-based).
  #     step       -- The current step (one-based).
  #     step_count -- The total number of steps.
  #     form       -- The Form instance for the current step (either empty
  #                   or with errors).
  #     previous_fields -- A string representing every previous data field,
  #                   plus hashes for completed forms, all in the form of
  #                   hidden fields. Note that you'll need to run this
  #                   through the 'safe' template filter, to prevent
  #                   auto-escaping, because it's raw HTML.

  context ||= {}
  # FIXME
  render_to_response(get_template(step),
                     context.merge(:step_field => step_field_name,
                                   :step0 => step,
                                   :step => step + 1,
                                   :step_count => num_steps,
                                   :form => form,
                                   :previous_fields => previous_fields),
                     :context_instance => RequestContext(request))
end

#security_hash(request, form) ⇒ Object



145
146
147
# File 'lib/bureaucrat/wizard.rb', line 145

def security_hash(request, form)
  Utils::security_hash(request, form)
end