jeffp-wizardly 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -117,17 +117,66 @@ for both cases
117
117
  act_wizardly_for :user, :redirect=>'/main'
118
118
  end
119
119
 
120
- ==== Other options
120
+ ==== Options For act_wizardly_for
121
121
 
122
122
  Here's a list of options you can use in the macro
123
123
 
124
124
  :completed => '/main/finished'
125
125
  :canceled => {:controller=>'main', :action=>'canceled'}
126
126
  :skip => true
127
+ :guard => false
127
128
  :mask_fields => [:password, :password_confirmation] (by default)
129
+ :persist_model => {:once|:per_page}
130
+ :form_data => {:sandbox|:session}
128
131
 
129
132
  Setting the :skip option to +true+ tells the scaffold helpers to include or exclude a skip button on each page.
130
133
  The :mask_fields options tells the scaffold generator which fields to generate as 'type=password' fields.
134
+ :persist_model and :form_data are explained below.
135
+
136
+
137
+ ==== Preserving Form Field Data
138
+
139
+ The :form_data option controls how the form data is preserved between
140
+ page requests that call outside the wizard controller. The default option setting,
141
+ :session, keeps the form data until the wizard is complete regardless of
142
+ whether the user leaves the wizard and returns later. The form
143
+ data is preserved for the life of the session or until the user completes the wizard.
144
+
145
+ The other option setting, :sandbox, clears the form data whenever
146
+ the user leaves the wizard before the wizard is complete. This includes pressing
147
+ a :cancel button, a hyperlink or plainly navigating somewhere else.
148
+ Upon returning to the wizard, the form is reset and the user starts fresh.
149
+
150
+ The form data is always cleared once the user has completed the wizard and the
151
+ database record has been created.
152
+
153
+ ==== Guarding Wizard Entry
154
+
155
+ The :guard option controls how a user may enter the wizard. If set to true, the
156
+ default, the wizard is guarded from entry anywhere except the first page. The wizard
157
+ controller will automatically redirect to the first page. When set to false, entry
158
+ may occur at any point. This may be useful for testing purposes and instances where
159
+ the application needs to navigate away and return to the wizard.
160
+
161
+ The guarding behavior works a little differently depending on the :form_data setting.
162
+ When :form_data is set to :session (the default behavior), guarding only occurs
163
+ for the initial entry. Once a user has entered the form and started it, while
164
+ form data is being kept, the application may thereafter enter anywhere. On the
165
+ contrary, if :form_data is set to :sandbox, entry is always guarded, and once the user
166
+ leaves the wizard, entry may only occur at the initial page (as the form data has
167
+ been reset).
168
+
169
+ ==== Saving The Model
170
+
171
+ The :persist_model option controls how the model is saved, either :once or :per_page.
172
+ The default option :once, only saves the model when the wizard is completed, by the
173
+ user pressing a :finish button or :next button on the final page. This method
174
+ prevents numerous incomplete models and possibly invalid models being saved to the
175
+ database.
176
+
177
+ The other option setting, :per_page, saves the model incrementally for each time
178
+ the form data validates as the user moves through the pages.
179
+
131
180
 
132
181
  === Buttons
133
182
 
@@ -263,6 +312,24 @@ call back for this.
263
312
  end
264
313
  end
265
314
 
315
+ === Creating Scaffolds
316
+
317
+ Wizard scaffolds can be created for any wizardly controller (one using the acts_wizardly_for
318
+ macro).
319
+
320
+ ./script/generate wizardly_scaffold controller_name --haml
321
+
322
+ The wizardly_scaffold generator will create HTML view scaffolds by default. Append a
323
+ --haml option to create scaffolds in HAML.
324
+
325
+ Sometimes you have already edited views from a scaffold but want to regenerate the
326
+ scaffold because of changes to your model without overwriting the current views.
327
+ Use the --underscore option to create corresponding views with an underscore prefixing
328
+ each page.
329
+
330
+ ./script/generate wizardly_scaffold controller_name --underscore
331
+
332
+
266
333
  == Advanced Configuration
267
334
 
268
335
  To be provided
@@ -8,14 +8,20 @@ module Wizardly
8
8
  module Wizard
9
9
  class Configuration
10
10
  attr_reader :pages, :completed_redirect, :canceled_redirect, :controller_name, :page_order
11
+
12
+ #enum_attr :persistance, %w(sandbox session database)
11
13
 
12
14
  def initialize(controller_name, opts) #completed_redirect = nil, canceled_redirect = nil)
13
15
  @controller_name = controller_name
14
16
  @completed_redirect = opts[:redirect] || opts[:completed] || opts[:when_completed] #format_redirect(completed_redirect)
15
17
  @canceled_redirect = opts[:redirect] || opts[:canceled] || opts[:when_canceled]
16
18
  @allow_skipping = opts[:skip] || opts[:allow_skip] || opts[:allow_skipping] || false
17
- @guard_entry = opts.key?(:guard) ? opts[:guard] : true
19
+ @guard_entry = opts.key?(:guard) ? opts[:guard] : true
18
20
  @password_fields = opts[:mask_fields] || opts[:mask_passwords] || [:password, :password_confirmation]
21
+ @persist_model = opts[:persist_model] || :once
22
+ @form_data = opts[:form_data] || :session
23
+ raise(ArgumentError, ":persist_model option must be one of :once or :per_page", caller) unless [:once, :per_page].include?(@persist_model)
24
+ raise(ArgumentError, ":form_data option must be one of :sandbox or :session", caller) unless [:sandbox, :session].include?(@form_data)
19
25
  @page_order = []
20
26
  @pages = {}
21
27
  @buttons = nil
@@ -25,6 +31,8 @@ module Wizardly
25
31
  end
26
32
  end
27
33
 
34
+ def persist_model_per_page?; @persist_model == :per_page; end
35
+ def form_data_keep_in_session?; @form_data == :session; end
28
36
  def model; @wizard_model_sym; end
29
37
  def model_instance_variable; "@#{@wizard_model_sym.to_s}"; end
30
38
  def model_class_name; @wizard_model_class_name; end
@@ -37,6 +45,11 @@ module Wizardly
37
45
  index += 1 unless self.last_page?(name)
38
46
  @page_order[index]
39
47
  end
48
+ def previous_page(name)
49
+ index = @page_order.index(name)
50
+ index -= 1 unless self.first_page?(name)
51
+ @page_order[index]
52
+ end
40
53
  def button_for_function(name); @default_buttons[name]; end
41
54
  def buttons
42
55
  return @buttons if @buttons
@@ -49,9 +49,14 @@ MACRO
49
49
  def index
50
50
  redirect_to :action=>:#{self.page_order.first}
51
51
  end
52
+
52
53
  INDEX
53
54
  mb.string
54
55
  end
56
+
57
+ def persist_key;
58
+ @persist_key ||= "wizardly_#{controller_name.to_s.underscore}_#{model}".to_sym
59
+ end
55
60
 
56
61
  def print_page_action_method(id)
57
62
  page = @pages[id]
@@ -64,8 +69,8 @@ MACRO
64
69
  @wizard = wizard_config
65
70
  @title = '#{page.title}'
66
71
  @description = '#{page.description}'
67
- h = (flash[:wizard_model]||{}).merge(params[:#{self.model}] || {})
68
- @#{self.model} = #{self.model_class_name}.new(h)
72
+ h = (self.wizard_form_data||{}).merge(params[:#{self.model}] || {})
73
+ @#{self.model} = build_wizard_model(h)
69
74
  if request.post? && callback_performs_action?(:on_post_#{id}_form)
70
75
  raise CallbackError, "render or redirect not allowed in :on_post_#{id}_form callback", caller
71
76
  end
@@ -87,31 +92,33 @@ MACRO
87
92
  ONE
88
93
  if self.last_page?(id)
89
94
  mb << <<-TWO
90
- return if callback_performs_action?(:on_#{id}_form_#{finish_button})
95
+ callback_performs_action?(:on_#{id}_form_#{finish_button})
91
96
  _on_wizard_#{finish_button}
92
97
  redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed?
93
98
  TWO
94
99
  elsif self.first_page?(id)
95
100
  mb << <<-THREE
96
101
  if button_id == :#{finish_button}
97
- return if callback_performs_action?(:on_#{id}_form_#{finish_button})
102
+ callback_performs_action?(:on_#{id}_form_#{finish_button})
98
103
  _on_wizard_#{finish_button} if button_id == :#{finish_button}
99
104
  redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed?
100
105
  return
101
106
  end
102
- session[:progression] = [:#{id}]
107
+ save_wizard_model! if wizard_config.persist_model_per_page?
108
+ # session[:progression] = [:#{id}]
103
109
  return if callback_performs_action?(:on_#{id}_form_#{next_button})
104
110
  redirect_to :action=>:#{self.next_page(id)}
105
111
  THREE
106
112
  else
107
113
  mb << <<-FOUR
108
114
  if button_id == :#{finish_button}
109
- return if callback_performs_action?(:on_#{id}_form_#{finish_button})
115
+ callback_performs_action?(:on_#{id}_form_#{finish_button})
110
116
  _on_wizard_#{finish_button} if button_id == :#{finish_button}
111
117
  redirect_to #{Utils.formatted_redirect(self.completed_redirect)} unless self.performed?
112
118
  return
113
119
  end
114
- session[:progression].push(:#{id})
120
+ save_wizard_model! if wizard_config.persist_model_per_page?
121
+ # session[:progression].push(:#{id})
115
122
  return if callback_performs_action?(:on_#{id}_form_#{next_button})
116
123
  redirect_to :action=>:#{self.next_page(id)}
117
124
  FOUR
@@ -119,7 +126,7 @@ MACRO
119
126
 
120
127
  mb << <<-ENSURE
121
128
  ensure
122
- flash[:wizard_model] = h.merge(@#{self.model}.attributes)
129
+ self.wizard_form_data = h.merge(@#{self.model}.attributes) if (@#{self.model} && !@completed)
123
130
  end
124
131
  end
125
132
  ENSURE
@@ -135,6 +142,8 @@ ENSURE
135
142
  protected
136
143
  def _on_wizard_#{finish}
137
144
  @#{self.model}.save_without_validation!
145
+ @completed = true
146
+ reset_wizard_form_data
138
147
  _wizard_final_redirect_to(:completed)
139
148
  end
140
149
  def _on_wizard_#{skip}
@@ -142,13 +151,13 @@ ENSURE
142
151
  end
143
152
  def _on_wizard_#{back}
144
153
  # TODO: fix progression management
145
- redirect_to(:action=>((session[:progression]||[]).pop || :#{self.page_order.first})) unless self.performed?
154
+ # redirect_to(:action=>((session[:progression]||[]).pop || :#{self.page_order.first})) unless self.performed?
155
+ redirect_to(:action=>wizard_config.previous_page(@step)) unless self.performed?
146
156
  end
147
157
  def _on_wizard_#{cancel}
148
158
  _wizard_final_redirect_to(:canceled)
149
159
  end
150
160
  def _wizard_final_redirect_to(which_redirect)
151
- flash.discard(:wizard_model)
152
161
  initial_referer = reset_wizard_session_vars
153
162
  unless self.performed?
154
163
  redir = (which_redirect == :completed ? wizard_config.completed_redirect : wizard_config.canceled_redirect) || initial_referer
@@ -175,12 +184,53 @@ ENSURE
175
184
  else
176
185
  session[:initial_referer] = nil
177
186
  end
178
- flash.discard(:wizard_model)
187
+ if wizard_config.form_data_keep_in_session?
188
+ return if self.wizard_form_data # if it has an id we've started a wizard
189
+ else
190
+ reset_wizard_form_data
191
+ end
179
192
  #{guard_line}
180
193
  redirect_to :action=>:#{first_page} unless (params[:action] || '') == '#{first_page}'
181
- end
194
+ end
182
195
  hide_action :guard_entry
183
196
 
197
+ def save_wizard_model!
198
+ @#{self.model}.save_without_validation!
199
+ if wizard_config.form_data_keep_in_session?
200
+ h = self.wizard_form_data
201
+ h['id'] = @#{self.model}.id
202
+ self.wizard_form_data= h
203
+ end
204
+ end
205
+ def build_wizard_model(params)
206
+ if (wizard_config.persist_model_per_page? && (model_id = params['id']))
207
+ _model = #{self.model_class_name}.find(model_id)
208
+ _model.attributes = params
209
+ _model
210
+ else
211
+ #{self.model_class_name}.new(params)
212
+ end
213
+ end
214
+ hide_action :build_wizard_model, :save_wizard_model!
215
+
216
+ def wizard_form_data=(hash)
217
+ if wizard_config.form_data_keep_in_session?
218
+ session[:#{self.persist_key}] = hash
219
+ else
220
+ if hash
221
+ flash[:#{self.persist_key}] = hash
222
+ else
223
+ flash.discard(:#{self.persist_key})
224
+ end
225
+ end
226
+ end
227
+
228
+ def reset_wizard_form_data; self.wizard_form_data = nil; end
229
+ def wizard_form_data
230
+ wizard_config.form_data_keep_in_session? ? session[:#{self.persist_key}] : flash[:#{self.persist_key}]
231
+ end
232
+ hide_action :wizard_form_data, :wizard_form_data=, :reset_wizard_form_data
233
+
184
234
  def render_wizard_form
185
235
  end
186
236
  hide_action :render_wizard_form
@@ -16,6 +16,7 @@ class WizardlyScaffoldGenerator < Rails::Generator::Base
16
16
  def add_options!(opt)
17
17
  opt.on('--haml', 'Generate scaffold for haml wizard') { |v| options[:output] = :haml }
18
18
  opt.on('--ajax', 'Generate scaffold for ajax wizard') { |v| options[:output] = :ajax }
19
+ opt.on('--underscore', 'Append an underscore to front of each file') { |v| options[:underscore] = true }
19
20
  end
20
21
 
21
22
 
@@ -62,10 +63,11 @@ class WizardlyScaffoldGenerator < Rails::Generator::Base
62
63
  #m.directory(File.join('test/functional', controller_class_path))
63
64
  #m.directory(File.join('public/stylesheets', class_path))
64
65
 
66
+ underscore = options[:underscore] ? '_' : ''
65
67
  pages.each do |id, page|
66
68
  m.template(
67
69
  "form.#{view_file_ext.first}",
68
- File.join('app/views', controller_class_path, controller_name, "#{id}.#{view_file_ext.last}"),
70
+ File.join('app/views', controller_class_path, controller_name, "#{underscore}#{id}.#{view_file_ext.last}"),
69
71
  :assigns=>{:id=>id, :page=>page}
70
72
  )
71
73
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeffp-wizardly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Patmon
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-11 00:00:00 -07:00
12
+ date: 2009-08-12 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15