wicked-focused 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.rvmrc +19 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +122 -0
- data/MIT-LICENSE +20 -0
- data/README.md +253 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/lib/wicked/action.rb +64 -0
- data/lib/wicked/controller/concerns/path.rb +29 -0
- data/lib/wicked/controller/concerns/render_redirect.rb +49 -0
- data/lib/wicked/controller/concerns/steps.rb +87 -0
- data/lib/wicked/engine.rb +4 -0
- data/lib/wicked/macros.rb +23 -0
- data/lib/wicked/wizard.rb +26 -0
- data/lib/wicked-focused.rb +25 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/bar_controller.rb +18 -0
- data/test/dummy/app/controllers/foo_controller.rb +19 -0
- data/test/dummy/app/controllers/jump_controller.rb +26 -0
- data/test/dummy/app/controllers/steps_controller.rb +18 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/bar.rb +9 -0
- data/test/dummy/app/views/bar/first.html.erb +5 -0
- data/test/dummy/app/views/bar/last_step.html.erb +3 -0
- data/test/dummy/app/views/bar/second.html.erb +3 -0
- data/test/dummy/app/views/foo/first.html.erb +1 -0
- data/test/dummy/app/views/foo/last_step.html.erb +1 -0
- data/test/dummy/app/views/foo/second.html.erb +1 -0
- data/test/dummy/app/views/jump/first.html.erb +1 -0
- data/test/dummy/app/views/jump/last_step.html.erb +1 -0
- data/test/dummy/app/views/jump/second.html.erb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/step_positions/_step_position.html.erb +9 -0
- data/test/dummy/app/views/step_positions/first.html.erb +1 -0
- data/test/dummy/app/views/step_positions/last_step.html.erb +1 -0
- data/test/dummy/app/views/step_positions/second.html.erb +1 -0
- data/test/dummy/config/application.rb +45 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +26 -0
- data/test/dummy/config/environments/production.rb +49 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wicked.rb +2 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +8 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/index.html +1 -0
- data/test/dummy/public/javascripts/application.js +2 -0
- data/test/dummy/public/javascripts/controls.js +965 -0
- data/test/dummy/public/javascripts/dragdrop.js +974 -0
- data/test/dummy/public/javascripts/effects.js +1123 -0
- data/test/dummy/public/javascripts/prototype.js +6001 -0
- data/test/dummy/public/javascripts/rails.js +202 -0
- data/test/dummy/public/stylesheets/.gitkeep +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/helpers_test.rb +40 -0
- data/test/integration/jump_test.rb +16 -0
- data/test/integration/navigation_test.rb +88 -0
- data/test/integration/steps_test.rb +32 -0
- data/test/support/integration_case.rb +5 -0
- data/test/test_helper.rb +30 -0
- data/test/wicked_test.rb +7 -0
- data/wicked-focused.gemspec +138 -0
- metadata +270 -0
data/.rvmrc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
ruby_string="ruby-1.9.3-p125"
|
4
|
+
gemset_name="wicked"
|
5
|
+
|
6
|
+
if rvm list strings | grep -q "${ruby_string}" ; then
|
7
|
+
|
8
|
+
rvm use "${ruby_string}@${gemset_name}" --create
|
9
|
+
|
10
|
+
# Complain if bundler isn't installed
|
11
|
+
if [[ -z "`gem which bundler 2>&1 | grep -v ERROR`" ]]; then
|
12
|
+
echo "You need bundler:"
|
13
|
+
echo ""
|
14
|
+
echo " gem install bundler"
|
15
|
+
echo ""
|
16
|
+
fi
|
17
|
+
else
|
18
|
+
echo "${ruby_string} was not found, please run 'rvm install ${ruby_string}' and then cd back into the project directory."
|
19
|
+
fi
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "activesupport" , ">= 3.0.7"
|
4
|
+
gem "rails" , ">= 3.0.7"
|
5
|
+
|
6
|
+
# with Action macros
|
7
|
+
gem 'focused_controller', :git => 'git://github.com/kristianmandrup/focused_controller.git'
|
8
|
+
|
9
|
+
|
10
|
+
group :development, :test do
|
11
|
+
gem 'rake'
|
12
|
+
gem 'jeweler', "~> 1.8.4"
|
13
|
+
gem "rcov", ">= 0"
|
14
|
+
gem "capybara", ">= 1.0.0"
|
15
|
+
gem "sqlite3"
|
16
|
+
gem "launchy"
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
|
21
|
+
# gem 'ruby-debug'
|
22
|
+
# gem 'ruby-debug19'
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/kristianmandrup/focused_controller.git
|
3
|
+
revision: 729d753a62abf4eadcfd76123f643973392bec3a
|
4
|
+
specs:
|
5
|
+
focused_controller (0.1.0)
|
6
|
+
actionpack (~> 3.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
abstract (1.0.0)
|
12
|
+
actionmailer (3.0.11)
|
13
|
+
actionpack (= 3.0.11)
|
14
|
+
mail (~> 2.2.19)
|
15
|
+
actionpack (3.0.11)
|
16
|
+
activemodel (= 3.0.11)
|
17
|
+
activesupport (= 3.0.11)
|
18
|
+
builder (~> 2.1.2)
|
19
|
+
erubis (~> 2.6.6)
|
20
|
+
i18n (~> 0.5.0)
|
21
|
+
rack (~> 1.2.1)
|
22
|
+
rack-mount (~> 0.6.14)
|
23
|
+
rack-test (~> 0.5.7)
|
24
|
+
tzinfo (~> 0.3.23)
|
25
|
+
activemodel (3.0.11)
|
26
|
+
activesupport (= 3.0.11)
|
27
|
+
builder (~> 2.1.2)
|
28
|
+
i18n (~> 0.5.0)
|
29
|
+
activerecord (3.0.11)
|
30
|
+
activemodel (= 3.0.11)
|
31
|
+
activesupport (= 3.0.11)
|
32
|
+
arel (~> 2.0.10)
|
33
|
+
tzinfo (~> 0.3.23)
|
34
|
+
activeresource (3.0.11)
|
35
|
+
activemodel (= 3.0.11)
|
36
|
+
activesupport (= 3.0.11)
|
37
|
+
activesupport (3.0.11)
|
38
|
+
addressable (2.2.7)
|
39
|
+
arel (2.0.10)
|
40
|
+
builder (2.1.2)
|
41
|
+
capybara (1.1.2)
|
42
|
+
mime-types (>= 1.16)
|
43
|
+
nokogiri (>= 1.3.3)
|
44
|
+
rack (>= 1.0.0)
|
45
|
+
rack-test (>= 0.5.4)
|
46
|
+
selenium-webdriver (~> 2.0)
|
47
|
+
xpath (~> 0.1.4)
|
48
|
+
childprocess (0.2.4)
|
49
|
+
ffi (~> 1.0.6)
|
50
|
+
erubis (2.6.6)
|
51
|
+
abstract (>= 1.0.0)
|
52
|
+
ffi (1.0.11)
|
53
|
+
git (1.2.5)
|
54
|
+
i18n (0.5.0)
|
55
|
+
jeweler (1.8.4)
|
56
|
+
bundler (~> 1.0)
|
57
|
+
git (>= 1.2.5)
|
58
|
+
rake
|
59
|
+
rdoc
|
60
|
+
json (1.6.4)
|
61
|
+
launchy (2.0.5)
|
62
|
+
addressable (~> 2.2.6)
|
63
|
+
mail (2.2.19)
|
64
|
+
activesupport (>= 2.3.6)
|
65
|
+
i18n (>= 0.4.0)
|
66
|
+
mime-types (~> 1.16)
|
67
|
+
treetop (~> 1.4.8)
|
68
|
+
mime-types (1.17.2)
|
69
|
+
multi_json (1.0.4)
|
70
|
+
nokogiri (1.5.0)
|
71
|
+
polyglot (0.3.3)
|
72
|
+
rack (1.2.5)
|
73
|
+
rack-mount (0.6.14)
|
74
|
+
rack (>= 1.0.0)
|
75
|
+
rack-test (0.5.7)
|
76
|
+
rack (>= 1.0)
|
77
|
+
rails (3.0.11)
|
78
|
+
actionmailer (= 3.0.11)
|
79
|
+
actionpack (= 3.0.11)
|
80
|
+
activerecord (= 3.0.11)
|
81
|
+
activeresource (= 3.0.11)
|
82
|
+
activesupport (= 3.0.11)
|
83
|
+
bundler (~> 1.0)
|
84
|
+
railties (= 3.0.11)
|
85
|
+
railties (3.0.11)
|
86
|
+
actionpack (= 3.0.11)
|
87
|
+
activesupport (= 3.0.11)
|
88
|
+
rake (>= 0.8.7)
|
89
|
+
rdoc (~> 3.4)
|
90
|
+
thor (~> 0.14.4)
|
91
|
+
rake (0.9.2.2)
|
92
|
+
rcov (0.9.11)
|
93
|
+
rdoc (3.12)
|
94
|
+
json (~> 1.4)
|
95
|
+
rubyzip (0.9.5)
|
96
|
+
selenium-webdriver (2.15.0)
|
97
|
+
childprocess (>= 0.2.1)
|
98
|
+
ffi (~> 1.0.9)
|
99
|
+
multi_json (~> 1.0.4)
|
100
|
+
rubyzip
|
101
|
+
sqlite3 (1.3.5)
|
102
|
+
thor (0.14.6)
|
103
|
+
treetop (1.4.10)
|
104
|
+
polyglot
|
105
|
+
polyglot (>= 0.3.1)
|
106
|
+
tzinfo (0.3.33)
|
107
|
+
xpath (0.1.4)
|
108
|
+
nokogiri (~> 1.3)
|
109
|
+
|
110
|
+
PLATFORMS
|
111
|
+
ruby
|
112
|
+
|
113
|
+
DEPENDENCIES
|
114
|
+
activesupport (>= 3.0.7)
|
115
|
+
capybara (>= 1.0.0)
|
116
|
+
focused_controller!
|
117
|
+
jeweler (~> 1.8.4)
|
118
|
+
launchy
|
119
|
+
rails (>= 3.0.7)
|
120
|
+
rake
|
121
|
+
rcov
|
122
|
+
sqlite3
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,253 @@
|
|
1
|
+
# Wicked Focused
|
2
|
+
|
3
|
+
This gem is [wicked](https://github.com/schneems/wicked) tweaked for use with [focused controller](https://github.com/jonleighton/focused_controller).
|
4
|
+
|
5
|
+
[](http://travis-ci.org/schneems/wicked)
|
6
|
+
|
7
|
+
Use wicked to make your Rails controllers into step-by-step wizards. To see Wicked in action check out the example [Rails app](https://github.com/schneems/wicked_example) or [watch the screencast](http://schneems.com/post/18437886598/wizard-ify-your-rails-controllers-with-wicked).
|
8
|
+
|
9
|
+
## Why
|
10
|
+
|
11
|
+
Many times I'm left wanting a RESTful way to display a step by step process that may or not be associated with a resource. Wicked gives the flexibility to do what I want while hiding all the really nasty stuff you shouldn't do in a controller to make this possible. At it's core Wicked is a RESTful(ish) state machine, but you don't need to know that, just use it.
|
12
|
+
|
13
|
+
## Install
|
14
|
+
|
15
|
+
Add this to your Gemfile
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'wicked-focused'
|
19
|
+
```
|
20
|
+
|
21
|
+
Then run `bundle install` and you're ready to start
|
22
|
+
|
23
|
+
## Quicklinks
|
24
|
+
|
25
|
+
* Build an object step-by-step using [Partial Validation of Active Record Objects](https://github.com/schneems/wicked/wiki/Partial-Validation-of-Active-Record-Objects)
|
26
|
+
* [Show Current Wizard Progress to User](https://github.com/schneems/wicked/wiki/Show-Current-Wizard-Progress-to-User)
|
27
|
+
* [Example App](https://github.com/schneems/wicked_example)
|
28
|
+
* [Screencast](http://schneems.com/post/18437886598/wizard-ify-your-rails-controllers-with-wicked)
|
29
|
+
* [Watch Railscasts episode: #346 Wizard Forms with Wicked](http://railscasts.com/episodes/346-wizard-forms-with-wicked)
|
30
|
+
|
31
|
+
## How
|
32
|
+
|
33
|
+
We are going to build an 'after signup' wizard. First create a controller:
|
34
|
+
|
35
|
+
```
|
36
|
+
rails g controller after_signup
|
37
|
+
```
|
38
|
+
|
39
|
+
Add Routes into `config/routes.rb`:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
resources :after_signup
|
43
|
+
```
|
44
|
+
|
45
|
+
Next include `Wicked::Wizard` in your controller
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
|
49
|
+
class AfterSignupController
|
50
|
+
# base Wizard Action class of Controller must be called 'Action'
|
51
|
+
# and must include of Wizard::Action
|
52
|
+
class Action < FocusedAction
|
53
|
+
include Wizard::Action
|
54
|
+
|
55
|
+
steps :confirm_password, :confirm_profile, :find_friends
|
56
|
+
end
|
57
|
+
|
58
|
+
# creates Focused Action :index
|
59
|
+
include Wicked::Wizard
|
60
|
+
|
61
|
+
```
|
62
|
+
|
63
|
+
The wizard is set to call steps in order in the show action, you can specify custom logic in your show using a case statement like below. To send someone to the first step in this wizard we can direct them to `after_signup_path(:confirm_password)`.
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
class AfterSignupController
|
67
|
+
class Action < FocusedAction
|
68
|
+
include Wizard::Action
|
69
|
+
|
70
|
+
steps :confirm_password, :confirm_profile, :find_friends
|
71
|
+
end
|
72
|
+
include Wicked::Wizard
|
73
|
+
|
74
|
+
class Show < Action
|
75
|
+
def run
|
76
|
+
wizard_redirect and return if super()
|
77
|
+
@user = current_user
|
78
|
+
case step
|
79
|
+
when :find_friends
|
80
|
+
@friends = @user.find_friends
|
81
|
+
end
|
82
|
+
render_wizard
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
**Note:** Wicked uses the `:id` parameter to control the flow of steps, if you need to have an id parameter, please use nested routes see [Partial Validation of Active Record Objects](https://github.com/schneems/wicked/wiki/Partial-Validation-of-Active-Record-Objects) for an example. It will need to be prefixed, for example a Product's `:id` would be `:product_id`
|
89
|
+
|
90
|
+
You'll need to call `render_wizard` at the end of your action to get the correct views to show up.
|
91
|
+
|
92
|
+
By default the wizard will render a view with the same name as the step. So for our controller `AfterSignupController` with a view path of `/views/after_signup/` if call the :confirm_password step, our wizard will render `/views/after_signup/confirm_password.html.erb`
|
93
|
+
|
94
|
+
Then in your view you can use the helpers to get to the next step.
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
<%= link_to 'skip', next_wizard_path %>
|
98
|
+
```
|
99
|
+
|
100
|
+
You can manually specify which wizard action you want to link to by using the wizard_path helper.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
<%= link_to 'skip', wizard_path(:find_friends) %>
|
104
|
+
```
|
105
|
+
|
106
|
+
In addition to showing sequential views we can update elements in our controller.
|
107
|
+
Note: Here we demonstrate the use of wicked macros.
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
class AfterSignupController
|
111
|
+
use_wicked_macros
|
112
|
+
|
113
|
+
wicked_base_action do
|
114
|
+
steps :confirm_password, :confirm_profile, :find_friends
|
115
|
+
end
|
116
|
+
|
117
|
+
wizard_action :update do
|
118
|
+
wizard do
|
119
|
+
@user = current_user
|
120
|
+
case step
|
121
|
+
when :confirm_password
|
122
|
+
@user.update_attributes(params[:user])
|
123
|
+
end
|
124
|
+
sign_in(@user, :bypass => true) # needed for devise
|
125
|
+
render_wizard @user
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
We're passing `render_wizard` our `@user` object here. If you pass an object into `render_wizard` it will show the next step if the object saves or re-render the previous view if it does not save.
|
132
|
+
|
133
|
+
To get to this update action, you simply need to submit a form that PUT's to the same url
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
|
137
|
+
<%= form_for @user, :url => wizard_path, :method => :put do |f| %>
|
138
|
+
<%= f.password_field :password %>
|
139
|
+
<%= f.password_field :password_confirmation %>
|
140
|
+
|
141
|
+
<%= f.submit "Change Password" %>
|
142
|
+
<% end %>
|
143
|
+
|
144
|
+
```
|
145
|
+
|
146
|
+
We explicitly tell the form to PUT above. If you forget this, you will get a warning about the create action not existing, or no route found for POST. Don't forget this.
|
147
|
+
|
148
|
+
In the controller if you find that you want to skip a step, you can do it simply by calling `skip_step`
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
|
152
|
+
wizard_action :show do
|
153
|
+
wizard do
|
154
|
+
@user = current_user
|
155
|
+
case step
|
156
|
+
when :find_friends
|
157
|
+
if @user.has_facebook_access_token?
|
158
|
+
@friends = @user.find_friends
|
159
|
+
else
|
160
|
+
skip_step
|
161
|
+
end
|
162
|
+
end
|
163
|
+
render_wizard
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
```
|
168
|
+
|
169
|
+
Now you've got a fully functioning AfterSignup controller! If you have questions or if you struggled with something, let me know on [twitter](http://twitter.com/schneems), and i'll try to make it better or make the docs better.
|
170
|
+
|
171
|
+
## Quick Reference
|
172
|
+
|
173
|
+
*Macros*
|
174
|
+
|
175
|
+
`use_wicked_macros` enables use of the Wicked macros. Otherwise you must explicitly create equivalent classes and methods.
|
176
|
+
|
177
|
+
`wicked_base_action name, &block`
|
178
|
+
|
179
|
+
Created the Focused Controller action base class, from which any Wizard Action class will inherit from.
|
180
|
+
|
181
|
+
`wizard_action name, &block`
|
182
|
+
|
183
|
+
Creates a Focused Controller action class inheriting from the base action class of the controller. The block contains the class definition.
|
184
|
+
|
185
|
+
`wizard`
|
186
|
+
|
187
|
+
Creates a `#run` method as "required" by a Focused Controller action class. The run method generated calls super which calls `setup_wizard` and also auto-handles redirects.
|
188
|
+
|
189
|
+
*View/URL Helpers*
|
190
|
+
|
191
|
+
```ruby
|
192
|
+
|
193
|
+
wizard_path # Grabs the current path in the wizard
|
194
|
+
wizard_path(:specific_step) # Url of the :specific_step
|
195
|
+
next_wizard_path # Url of the next step
|
196
|
+
previous_wizard_path # Url of the previous step
|
197
|
+
|
198
|
+
# These only work while in a Wizard, and are not absolute paths
|
199
|
+
# You can have multiple wizards in a project with multiple `wizard_path` calls
|
200
|
+
```
|
201
|
+
|
202
|
+
*Controller Tidbits:*
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
steps :first, :second # Sets the order of steps
|
206
|
+
step # Gets symbol of current step
|
207
|
+
next_step # Gets symbol of next step
|
208
|
+
skip_step # Tells render_wizard to skip to the next logical step
|
209
|
+
render_wizard # Renders the current step
|
210
|
+
render_wizard(@user) # Shows next_step if @user.save, otherwise renders current step
|
211
|
+
```
|
212
|
+
|
213
|
+
Finally:
|
214
|
+
|
215
|
+
Don't forget to create your named views
|
216
|
+
|
217
|
+
```
|
218
|
+
app/
|
219
|
+
views/
|
220
|
+
controller_name/
|
221
|
+
first.html.erb
|
222
|
+
second.html.erb
|
223
|
+
# ...
|
224
|
+
```
|
225
|
+
|
226
|
+
# Finish Wizard Path
|
227
|
+
|
228
|
+
You can specify the url that your user goes to by over-riding the `finish_wizard_path` in your wizard controller action.
|
229
|
+
|
230
|
+
|
231
|
+
```
|
232
|
+
def finish_wizard_path
|
233
|
+
user_path(current_user)
|
234
|
+
end
|
235
|
+
```
|
236
|
+
|
237
|
+
### Testing with RSpec
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
# Test find_friends block of show action
|
241
|
+
get :show, :id => :find_friends
|
242
|
+
|
243
|
+
# Test find_friends block of update action
|
244
|
+
put :update, {'id' => 'find_friends', "user" => { "id" => @user.id.to_s }}
|
245
|
+
```
|
246
|
+
|
247
|
+
## About
|
248
|
+
|
249
|
+
Please poke around the source code, if you see easier ways to get a Rails controller do do what I want, let me know.
|
250
|
+
|
251
|
+
If you have a question file an issue or, find me on the Twitters [@schneems](http://twitter.com/schneems).
|
252
|
+
|
253
|
+
This project rocks and uses MIT-LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler'
|
4
|
+
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development, :test)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rake'
|
14
|
+
require 'rdoc/task'
|
15
|
+
|
16
|
+
require 'rake/testtask'
|
17
|
+
|
18
|
+
Rake::TestTask.new(:test) do |t|
|
19
|
+
t.libs << 'lib'
|
20
|
+
t.libs << 'test'
|
21
|
+
t.pattern = 'test/**/*_test.rb'
|
22
|
+
t.verbose = false
|
23
|
+
end
|
24
|
+
|
25
|
+
task :default => :test
|
26
|
+
|
27
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
28
|
+
rdoc.rdoc_dir = 'rdoc'
|
29
|
+
rdoc.title = 'Wicked Focused'
|
30
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
31
|
+
rdoc.rdoc_files.include('README.rdoc')
|
32
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
require 'jeweler'
|
37
|
+
Jeweler::Tasks.new do |gem|
|
38
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
39
|
+
gem.name = "wicked-focused"
|
40
|
+
gem.homepage = "http://github.com/schneems/wicked"
|
41
|
+
gem.license = "MIT"
|
42
|
+
gem.summary = %Q{Use Wicked to turn your Focused Controller into a wizard}
|
43
|
+
gem.description = %Q{Rails engine for producing Focused Controller based wizards}
|
44
|
+
gem.email = "kmandrup@gmail.com"
|
45
|
+
gem.authors = ["kristianmandrup", "schneems"]
|
46
|
+
# dependencies defined in Gemfile
|
47
|
+
end
|
48
|
+
Jeweler::RubygemsDotOrgTasks.new
|
49
|
+
|
50
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Wicked
|
2
|
+
module Action
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
# Include the modules!!
|
6
|
+
include Wicked::Controller::Concerns::Path
|
7
|
+
include Wicked::Controller::Concerns::RenderRedirect
|
8
|
+
include Wicked::Controller::Concerns::Steps
|
9
|
+
|
10
|
+
included do
|
11
|
+
# Give our Views helper methods!
|
12
|
+
helper_method :wizard_path, :next_wizard_path, :previous_wizard_path,
|
13
|
+
:step, :wizard_steps, :current_step?,
|
14
|
+
:past_step?, :future_step?, :previous_step?,
|
15
|
+
:next_step?
|
16
|
+
end
|
17
|
+
|
18
|
+
# any subclass (Action class) should call super!
|
19
|
+
def run
|
20
|
+
setup_wizard
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
def wizard &block
|
25
|
+
define_method :run do
|
26
|
+
wizard_redirect and return if super()
|
27
|
+
instance_eval &block
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def setup_wizard
|
35
|
+
@redirect_path = wizard_path(steps.first) if first_step? && !on_first_step?
|
36
|
+
@redirect_path = wizard_path(steps.last) if last_step? && !on_last_step?
|
37
|
+
|
38
|
+
@step = params[:id].try(:to_sym) || steps.first
|
39
|
+
@previous_step = previous_step(@step)
|
40
|
+
@next_step = next_step(@step)
|
41
|
+
@redirect_path
|
42
|
+
end
|
43
|
+
|
44
|
+
def wizard_redirect
|
45
|
+
redirect_to @redirect_path if @redirect_path
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_first_step?
|
49
|
+
step == steps.first
|
50
|
+
end
|
51
|
+
|
52
|
+
def on_last_step?
|
53
|
+
step == steps.first
|
54
|
+
end
|
55
|
+
|
56
|
+
def first_step?
|
57
|
+
params[:id].try(:to_sym) == :wizard_first
|
58
|
+
end
|
59
|
+
|
60
|
+
def last_step?
|
61
|
+
params[:id].try(:to_sym) == :wizard_last
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Wicked::Controller::Concerns::Path
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
def next_wizard_path(options = {})
|
5
|
+
wizard_path(@next_step, options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def previous_wizard_path(options = {})
|
9
|
+
wizard_path(@previous_step, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def wicked_controller
|
13
|
+
self.class.name.sub(/::\w+$/, '')
|
14
|
+
end
|
15
|
+
|
16
|
+
def wicked_controller_name
|
17
|
+
wicked_controller.sub(/Controller$/, '').gsub('::', '_').underscore
|
18
|
+
end
|
19
|
+
|
20
|
+
def wicked_action
|
21
|
+
params[:action]
|
22
|
+
end
|
23
|
+
|
24
|
+
def wizard_path(goto_step = nil, options = {})
|
25
|
+
id = goto_step || params[:id]
|
26
|
+
path_method = "#{wicked_controller_name}_path"
|
27
|
+
send path_method, id, options
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Wicked::Controller::Concerns::RenderRedirect
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
|
5
|
+
def render_wizard(resource = nil, options = {})
|
6
|
+
process_resource!(resource)
|
7
|
+
if @skip_to
|
8
|
+
redirect_to wizard_path(@skip_to), options
|
9
|
+
else
|
10
|
+
render_step @step, options
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_resource!(resource)
|
15
|
+
if resource
|
16
|
+
if resource.save
|
17
|
+
@skip_to ||= @next_step
|
18
|
+
else
|
19
|
+
@skip_to = nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def render_step(the_step, options = {})
|
25
|
+
if the_step.nil? || the_step == :finish
|
26
|
+
redirect_to_finish_wizard options
|
27
|
+
else
|
28
|
+
render the_step, options
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def redirect_to_next(next_step)
|
33
|
+
if next_step.nil?
|
34
|
+
redirect_to_finish_wizard
|
35
|
+
else
|
36
|
+
redirect_to wizard_path(next_step)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# TODO redirect to resource if one is passed to render_wizard
|
41
|
+
def finish_wizard_path
|
42
|
+
'/'
|
43
|
+
end
|
44
|
+
|
45
|
+
def redirect_to_finish_wizard(options = nil)
|
46
|
+
redirect_to finish_wizard_path, options
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|