Permalink
Browse files

added route helper

  • Loading branch information...
1 parent 99bf674 commit 3b72d6153bed48b942d2752f4fdcd1c919e8dc27 @ssendev ssendev committed Aug 26, 2012
View
@@ -85,6 +85,30 @@ The wizard is set to call steps in order in the show action, you can specify cus
**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 [building objects with wicked](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`
+### Routing helpers
+
+The routing helper which was loaned from Wizardry(https://raw.github.com/lexmag/wizardry) allows for nicer routes
+
+```ruby
+resource :after_signup do
+ is_wicked
+end
+# same as
+wicked_resource :after_signup
+# or
+wicked_resources :products
+```
+
+will replace default *:id/edit* path with *:id/edit/:step* and update with *:id/:step*.
+`is_wicked` and wicked_resource also accepts a hash to further configure the behavior
+
+* `:step_constraint => /first/second/` Set to true to generate a regexp which allows only the steps which are assigned in the controller or pass a regexp.
+* `:step_optional => true` The route will be `*:id/edit(/:step)*` but be carefull not to shadow other routes.
+* `:step_parameter => :pets` Defaults to :step can but can be changed set to :id for backwards compatibility with the old routes.
+* `:show_step_action => :show` the action used to display the steps, defaults to :edit but can be set back to :show.
+wicked_resource(s) or the parent resource from is_wicked can take:
+* `:path_names => { :edit => 'amend' }` Changes the route to `*:id/amend/:step*` can be set to nil for `*:id/:step*`.
+
You'll need to call `render_wizard` at the end of your action to get the correct views to show up.
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`
View
@@ -1,3 +1,4 @@
+
module Wicked
module Controller
module Concerns
@@ -11,4 +12,5 @@ module Wizard
require 'wicked/controller/concerns/steps'
require 'wicked/controller/concerns/path'
require 'wicked/wizard'
-require 'wicked/engine'
+require 'wicked/engine'
+require 'wicked/routes'
@@ -21,8 +21,8 @@ def wicked_action
def wizard_path(goto_step = nil, options = {})
options = { :controller => wicked_controller,
- :action => 'show',
- :id => goto_step || params[:id],
+ :action => wicked_step_action,
+ wicked_step_parameter.to_sym => goto_step || params[wicked_step_parameter],
:only_path => true
}.merge options
url_for(options)
@@ -47,6 +47,8 @@ module ClassMethods
def steps(*args)
options = args.extract_options!
steps = args
+ class_attribute :wicked_steps, instance_writer: false
+ self.wicked_steps = steps
prepend_before_filter(options) do
self.steps = steps
end
View
@@ -0,0 +1,69 @@
+# inspired by https://github.com/lexmag/wizardry/blob/master/lib/wizardry/routes.rb
+
+class ActionDispatch::Routing::Mapper
+ def is_wicked(opts = {})
+ unless resource_scope?
+ raise ArgumentError, "can't use is_wicked outside resource(s) scope"
+ end
+
+ draw = { :update => true, :edit => true }
+
+ options = @scope[:scope_level_resource].options
+
+ except = Array.wrap(options.delete(:except)).map(&:to_sym)
+ only = Array.wrap(options.delete(:only)).map(&:to_sym)
+
+ only_was_present = only.present?
+ if only_was_present = only.present?
+ only.each { |action| except.delete(action) if except.include?(action) } # discard contradicting options
+ draw.each { |k,v| draw[k] = only.delete(k) == k }
+ end
+ draw.each { |k,v| draw[k] = v && ! except.include?(k) } if except.present?
+
+ options.merge!(only: only) if only_was_present
+ except += draw.keys
+ options.merge!(except: except.uniq)
+
+ controller = @scope[:controller].to_s.dup.concat('_controller').classify.constantize rescue nil
+ controller = @scope[:controller].to_s.singularize.concat('_controller').classify.constantize unless controller.present?
+
+ step_parameter = opts.delete(:step_parameter).try(:to_s) || 'step'
+ controller.class_attribute :wicked_step_parameter, instance_writer: false unless defined? controller.wicked_step_parameter
+ controller.wicked_step_parameter = step_parameter
+ step_action = opts.delete(:show_step_action).try(:to_s) || 'edit'
+ controller.class_attribute :wicked_step_action, instance_writer: false unless defined? controller.wicked_step_action
+ controller.wicked_step_action = step_action
+
+ path_name = 'edit'
+ path_name = @scope[:path_names][:edit] if @scope[:path_names].key? :edit
+ step = opts.delete(:step_optional) ? "(/:#{step_parameter})" : "/:#{step_parameter}"
+ step = step.sub(/\//, '') unless path_name
+ edit_params = {"#{path_name}#{step}" => step_action.to_sym, as: step_action.to_sym, on: :member}
+ update_params = {"#{step}" => :update, as: :update, on: :member}
+
+ step_constraint = opts.delete(:step_constraint)
+ step_constraint = Regexp.new controller.wicked_steps.join('|') if step_constraint == true
+ if step_constraint
+ edit_params.merge! step_parameter.to_sym => step_constraint
+ update_params.merge! step_parameter.to_sym => step_constraint
+ end
+
+ get edit_params if draw[:edit]
+ put update_params if draw[:update]
+
+ end
+
+ [:resources, :resource].each do |method|
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
+ def wicked_#{method}(*res) # def wicked_resources(*res)
+ wicked_options = res.extract_options! # wicked_options = res.extract_options!
+ options = wicked_options.slice! :step_constraint, :step_optional, :step_parameter, :show_step_action # options = wicked_options.slice :step_constraint, :step_optional, :step_parameter, :show_step_action
+ res.push options if options.present? # res.push options if options.present?
+ #{method} *res do # resources *res do
+ is_wicked wicked_options # is_wicked wicked_options
+ yield if block_given? # yield if block_given?
+ end # end
+ end # end
+ EOT
+ end
+end
View
@@ -15,6 +15,11 @@ module Wizard
:next_step?
# Set @step and @next_step variables
before_filter :setup_wizard
+
+ self.class_attribute :wicked_step_parameter, instance_writer: false unless defined? wicked_step_parameter
+ self.wicked_step_parameter ||= :id
+ self.class_attribute :wicked_step_action, instance_writer: false unless defined? wicked_step_action
+ self.wicked_step_action ||= 'show'
end
def index
@@ -23,10 +28,10 @@ def index
private
def setup_wizard
- redirect_to wizard_path(steps.first) if params[:id].try(:to_sym) == :wizard_first
- redirect_to wizard_path(steps.last) if params[:id].try(:to_sym) == :wizard_last
+ redirect_to wizard_path(steps.first) if params[wicked_step_parameter].try(:to_sym) == :wizard_first
+ redirect_to wizard_path(steps.last) if params[wicked_step_parameter].try(:to_sym) == :wizard_last
- @step = params[:id].try(:to_sym) || steps.first
+ @step = params[wicked_step_parameter].try(:to_sym) || steps.first
@previous_step = previous_step(@step)
@next_step = next_step(@step)
end
@@ -0,0 +1,14 @@
+## This controller uses includes
+
+class Bar2Controller < ApplicationController
+ include Wicked::Wizard
+ steps :first, :second, :last_step
+
+ def edit
+ skip_step if params[:skip_step]
+ render_wizard
+ end
+
+ def update
+ end
+end
@@ -0,0 +1,13 @@
+## This controller uses inheritance
+
+class Foo2Controller < Wicked::WizardController
+ steps :first, :second, :last_step
+
+ def edit
+ skip_step if params[:skip_step]
+ render_wizard
+ end
+
+ def update
+ end
+end
@@ -0,0 +1,22 @@
+## This controller uses includes
+
+class Jump2Controller < ApplicationController
+ include Wicked::Wizard
+ steps :first, :second, :last_step
+
+ def edit
+ skip_step if params[:skip_step]
+ jump_to :last_step if params[:jump_to]
+ if params[:resource]
+ value = params[:resource][:save] == 'true'
+ @bar = Bar.new(value)
+ render_wizard(@bar)
+ else
+ render_wizard
+ end
+ end
+
+ def update
+ end
+
+end
@@ -0,0 +1,6 @@
+## This controller uses includes
+
+class ProductsController < ApplicationController
+ include Wicked::Wizard
+ steps :first, :second, :last_step
+end
@@ -0,0 +1,13 @@
+## This controller uses includes
+
+class StepPositions2Controller < ApplicationController
+ include Wicked::Wizard
+ steps :first, :second, :last_step
+
+ def edit
+ render_wizard
+ end
+
+ def update
+ end
+end
@@ -0,0 +1,5 @@
+first
+
+<%= link_to 'last', wizard_path(:last_step) %>
+<%= link_to 'current', wizard_path %>
+<%= link_to 'skip', next_wizard_path %>
@@ -0,0 +1,3 @@
+last_step
+
+<%= "step #{wizard_steps.index(step) + 1 } of #{wizard_steps.count}" %>
@@ -0,0 +1,3 @@
+second
+
+<%= link_to 'previous', previous_wizard_path %>
@@ -0,0 +1 @@
+first
@@ -0,0 +1 @@
+last_step
@@ -0,0 +1 @@
+second
@@ -0,0 +1 @@
+first
@@ -0,0 +1 @@
+last_step
@@ -0,0 +1 @@
+second
@@ -0,0 +1,9 @@
+<% wizard_steps.each do |s| %>
+ <p>
+ <%= "#{s} step is the current step" if current_step?(s) %><br />
+ <%= "#{s} step is a past step" if past_step?(s) %><br />
+ <%= "#{s} step is a future step" if future_step?(s) %><br />
+ <%= "#{s} step was the previous step" if previous_step?(s) %><br />
+ <%= "#{s} step is the next step" if next_step?(s) %><br />
+ </p>
+<% end %>
@@ -0,0 +1 @@
+<%= render 'step_position' %>
@@ -0,0 +1 @@
+<%= render 'step_position' %>
@@ -0,0 +1 @@
+<%= render 'step_position' %>
@@ -1,8 +1,16 @@
Dummy::Application.routes.draw do
resources :foo
+ wicked_resource :foo2, controller: :foo2
resources :bar
+ wicked_resource :bar2, controller: :bar2
resources :jump
+ wicked_resource :jump2, controller: :jump2
resources :step_positions
+ wicked_resource :step_positions2, controller: :step_positions2
+ resources :products, except: :destroy, path_names: { new: :make } do
+ get :commit, on: :collection
+ is_wicked step_constraint: true
+ end
# The priority is based upon order of creation:
# first created -> highest priority.
@@ -13,4 +13,19 @@ class JumpNavigationTest < ActiveSupport::IntegrationCase
assert has_content?('first')
assert !has_content?('last_step')
end
+end
+
+class JumpNavigationEditTest < ActiveSupport::IntegrationCase
+ test 'consider jump_to when calling render_wizard with resource' do
+ step = :first
+ visit(edit_jump2_path(nil, step: step, :resource => {:save => true}, :jump_to => :last_step))
+ assert has_content?('last_step')
+ end
+
+ test 'disregard jump_to when saving the resource fails' do
+ step = :first
+ visit(edit_jump2_path(nil, step: step, :resource => {:save => false}, :jump_to => :last_step))
+ assert has_content?('first')
+ assert !has_content?('last_step')
+ end
end
Oops, something went wrong.

0 comments on commit 3b72d61

Please sign in to comment.