Code Monkey home page Code Monkey logo

wicked's Introduction

Step-By-Step Wizard Controllers

Build Status Code Climate Help Contribute to Open Source

Use wicked to make your Rails controllers into step-by-step wizards. To see Wicked in action check out the example Rails app or watch the screencast.

Why

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 its core Wicked is a RESTful(ish) state machine, but you don't need to know that, just use it.

Install

Add this to your Gemfile

gem 'wicked'

Then run bundle install and you're ready to start

Quicklinks

How

We are going to build an 'after signup' wizard. If you don't have a current_user then check out how to Build a step-by-step object with Wicked.

First create a controller:

rails g controller after_signup

Add Routes into config/routes.rb:

resources :after_signup

Next include Wicked::Wizard in your controller

class AfterSignupController < ApplicationController
  include Wicked::Wizard

  steps :confirm_password, :confirm_profile, :find_friends
  # ...

You can also use the old way of inheriting from Wicked::WizardController.

class AfterSignupController < Wicked::WizardController

  steps :confirm_password, :confirm_profile, :find_friends
  # ...

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).

class AfterSignupController < ApplicationController
  include Wicked::Wizard

  steps :confirm_password, :confirm_profile, :find_friends

  def show
    @user = current_user
    case step
    when :find_friends
      @friends = @user.find_friends
    end
    render_wizard
  end
end

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 for an example. It will need to be prefixed, for example a Product's :id would be :product_id

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

Then in your view you can use the helpers to get to the next step.

<%= link_to 'skip', next_wizard_path %>

You can manually specify which wizard action you want to link to by using the wizard_path helper.

<%= link_to 'skip', wizard_path(:find_friends) %>

In addition to showing sequential views we can update elements in our controller.

class AfterSignupController < ApplicationController
  include Wicked::Wizard

  steps :confirm_password, :confirm_profile, :find_friends

  def update
    @user = current_user
    case step
    when :confirm_password
      @user.update(user_params)
    end
    sign_in(@user, bypass: true) # needed for devise
    render_wizard @user
  end
  
  private
  def user_params
    params.require(:user)
          .permit(:email, :current_password) # ...
  end
end

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.

Note that render_wizard does attempt to save the passed object. This means that in the above example, the object will be saved twice. This will cause any callbacks to run twice also. If this is undesirable for your use case, then calling assign_attributes (which does not save the object) instead of update might work better.

To get to this update action, you simply need to submit a form that PUT's to the same url

<%= form_for @user, url: wizard_path, method: :put do |f| %>
  <%=  f.password_field :password  %>
  <%=  f.password_field :password_confirmation  %>

  <%= f.submit "Change Password" %>
<% end %>

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.

In the controller if you find that you want to skip a step, you can do it simply by calling skip_step

def show
  @user = current_user
  case step
  when :find_friends
    if @user.has_facebook_access_token?
      @friends = @user.find_friends
    else
      skip_step
    end
  end
  render_wizard
end

Now you've got a fully functioning AfterSignup controller! If you have questions or if you struggled with something, let me know on twitter, and i'll try to make it better or make the docs better.

Quick Reference

View/URL Helpers:

wizard_path                  # relative url of the current step
wizard_path(:specific_step)  # relative url of a :specific_step
next_wizard_path             # relative url of the next step
previous_wizard_path         # relative url of the previous step

wizard_url                  # fully qualified url of the current step
wizard_url(:specific_step)  # fully qualified url of a :specific_step
next_wizard_url             # fully qualified url of the next step
previous_wizard_url         # fully qualified url of the previous step

# These only work while in a Wizard
# You can have multiple wizards in a project with multiple `wizard_path` calls

Controller Tidbits:

steps  :first, :second                        # Sets the order of steps
step                                          # Gets current step
next_step                                     # Gets next step
previous_step                                 # Gets previous step
skip_step                                     # Tells render_wizard to skip to the next logical step
jump_to(:specific_step)                       # Jump to :specific_step
render_wizard                                 # Renders the current step
render_wizard(@user)                          # Shows next_step if @user.save, otherwise renders
render_wizard(@user, context: :account_setup) # Shows next_step if @user.save(context: :account_setup), otherwise renders
wizard_steps                                  # Gets ordered list of steps
current_step?(step)                           # is step the same as the current request's step
past_step?(step)                              # does step come before the current request's step in wizard_steps
future_step?(step)                            # does step come after the current request's step in wizard_steps
previous_step?(step)                          # is step immediately before the current request's step
next_step?(step)                              # is step immediately after the current request's step

Redirect options

Both skip_step and jump_to will cause a redirect.

skip_step(foo: "bar")

Note that unlike you would do when making a call to Rails' redirect_to, you should not call return immediately after skip_step and jump_to, since the actual redirection is done in the render_wizard call.

If you want to pass params to the step you are skipping to you can pass it into those:

jump_to(:specific_step, foo: "bar")

Finally:

Don't forget to create your named views

app/
  views/
    controller_name/
      first.html.erb
      second.html.erb
      # ...

Finish Wizard Path

You can specify the url that your user goes to by over-riding the finish_wizard_path in your wizard controller.

def finish_wizard_path
  user_path(current_user)
end

Testing with RSpec

# Test find_friends block of show action
get :show, params: { id: :find_friends }

# Test find_friends block of update action
patch :update, params: {'id' => 'find_friends', "user" => { "id" => @user.id.to_s }}

Internationalization of URLS (I18n)

If your site works in multiple languages, or if you just want more control over how your URLs look you can now use I18n with wicked. To do so you need to replace this:

include Wicked::Wizard

With this:

include Wicked::Wizard::Translated

This will allow you to specify translation keys instead of literal step names. Let's say you've got steps that look like this:

steps :first, :second

So the urls would be /after_signup/first and /after_signup/second. But you want them to show up differently for different locales. For example someone coming form a Spanish speaking locale should see /after_signup/uno and after_signup/dos.

To internationalize first you need to create your locales files under config/locales such as config/locales/es.yml for Spanish. You then need to add a first and second key under a wicked key like this:

es:
  hello: "hola mundo"
  wicked:
    first: "uno"
    second: "dos"

It would also be a good idea to create a english version under config/locales/en.yml or your english speaking friends will get errors. If your app already uses I18n you don't need to do anything else, if not you will need to make sure that you set the I18n.locale on each request you could do this somewhere like a before filter in your application_controller.rb

before_action :set_locale

private

def set_locale
  I18n.locale = params[:locale] if params[:locale].present?
end

def default_url_options(options = {})
  {locale: I18n.locale}
end

For a screencast on setting up and using I18n check out Railscasts. You can also read the free I18n Rails Guide.

Now when you visit your controller with the proper locale set your URLs should be more readable like /after_signup/uno and after_signup/dos.

Wicked expects your files to be named the same as your keys, so when a user visits after_signup/dos with the es locale it will render the second.html.erb file.

Important: When you do this the value of step as well as next_step and previous_step and all the values within steps will be translated to what locale you are using. To translate them to the "canonical" values that you've have in your controller you'll need so use wizard_value method.

For example, if you had this in your controller, and you converted it to a use Wicked translations, so this will not work:

steps :confirm_password, :confirm_profile, :find_friends

def show
  case step
  when :find_friends
    @friends = current_user.find_friends
  end
  render_wizard
end

Instead you need to use wizard_value to get the "reverse translation" in your controller code like this:

steps :confirm_password, :confirm_profile, :find_friends

def show
  case wizard_value(step)
  when :find_friends
    @friends = current_user.find_friends
  end
  render_wizard
end

The important thing to remember is that step and the values in steps are always going to be in the same language if you're using the Wicked translations. If you need any values to match the values set directly in your controller, or the names of your files (i.e. views/../confirm_password.html.erb, then you need to use wizard_value method.

Custom URLs

Very similar to using I18n from above but instead of making new files for different languages, you can stick with one language. Make sure you are using the right module:

include Wicked::Wizard::Translated

Then you'll need to specify translations in your language file. For me, the language I'm using is english so I can add translations to config/locales/en.yml

en:
  hello: "hello world"
  wicked:
    first: "verify_email"
    second: "if_you_are_popular_add_friends"

Now you can change the values in the URLs to whatever you want without changing your controller or your files, just modify your en.yml. If you're not using English you can set your default_locale to something other than en in your config/application.rb file.

config.i18n.default_locale = :de

Important: Don't forget to use wizard_value() method to make sure you are using the right canonical values of step, previous_step, next_step, etc. If you are comparing them to non wicked generate values.

Custom crafted wizard urls: just another way Wicked makes your app a little more saintly.

Dynamic Step Names

If you wish to set the order of your steps dynamically you can do this by manually calling and self.steps = [# <some steps> ] in a before_action method. Then call before_action :setup_wizard after so that wicked knows when it is safe to initializelike this:

include Wicked::Wizard
before_action :set_steps
before_action :setup_wizard

# ...

private
def set_steps
  if params[:flow] == "twitter"
    self.steps = [:ask_twitter, :ask_email]
  elsif params[:flow] == "facebook"
    self.steps = [:ask_facebook, :ask_email]
  end
end

NOTE: The order of the before_action matters, when setup_wizard is called it will validate the presence of self.steps, you must call your custom step setting code before this point.

Send params to finish_wizard_path method

If you wish to send parameters to the finish_wizard_path method that can be done by adding to your controller the method with the params argument def finish_wizard_path(params) ... end.

In order to send the parameters to the method here is an example of the show method:

steps :first_step, :second_step

def show
  # ...
  render_wizard(nil, {}, { hello: 'world' })
end

def update
  # ...
  render_wizard(@user, {}, { hello: 'world' })
end

def finish_wizard_path(params)
  # here you can access params and that would be equal to { hello: 'world' }
end

The wizard_path and next_wizard_path methods also take parameters that can then be accessed or visible in the show and update actions of the controller. You can use the methods like so:

next_wizard_path({ hello: 'world' })
wizard_path(nil, { hello: 'world' })
# the wizard_path with the step specified would look like this
wizard_path(:wicked_finish, wizard_id: @user.id, hello: 'world')

Keywords

There are a few "magical" keywords that will take you to the first step, the last step, or the "final" action (the redirect that happens after the last step). Prior to version 0.6.0 these were hardcoded strings. Now they are constants which means you can access them or change them. They are:

Wicked::FIRST_STEP
Wicked::LAST_STEP
Wicked::FINISH_STEP

You can build links using these constants after_signup_path(Wicked::FIRST_STEP) which will redirect the user to the first step you've specified. This might be useful for redirecting a user to a step when you're not already in a Wicked controller. If you change the constants, they are expected to be strings (not symbols).

Support

Most problems using this library are general problems using Ruby/Rails. If you cannot get something to work correctly please open up a question on stack overflow. If you've not posted there before, provide a description of the problem you're having and usually some example code and a copy of your rails logs helps.

If you've found a bug, please open a ticket on the issue tracker with a small example app that reproduces the behavior.

About

Made by @schneems.

This project rocks and uses MIT-LICENSE.

Compatibility

Refer to the Travis CI test matrix for test using your version of Ruby and Rails. If there is a newer Ruby or Rails you don't see on there, please add an entry to the Appraisals file, then run $ appraisals install and update the .travis.yml file and send me a pull request.

Note: Rails 3.0 support is only for Ruby 1.9.3 or JRuby, not Ruby 2.0.0 or newer.

Running Gem Tests

First, install the development gems:

$ bundle install

Now that appraisal is installed, use it to set up all the gemfiles for the test matrix:

$ appraisal install

Then to run tests against all the appraisal gemfiles, use:

$ appraisal rake test

To run tests against one specific gemfile, use

$ appraisal 4.1 rake test

Note that Rails 3.0 tests don't pass in Ruby 2.0.0 or newer, so during development it may be easier to disable this gemfile if you are using a current version of Ruby.

Contributing

See the Contributing guide.

wicked's People

Contributors

aaronmcadam avatar ahorner avatar bo-oz avatar bshelton229 avatar chocksy avatar deepakmahakale avatar drewhoffer avatar frozenfung avatar fschwahn avatar gokure avatar hwo411 avatar interhive avatar iseth avatar lucatironi avatar michael-garland avatar michaeldowse avatar mishina2228 avatar nruth avatar parndt avatar petergoldstein avatar pragmaticivan avatar racheldonovan avatar rcmc2 avatar reinaris avatar robertaudi avatar schneems avatar seanahrens avatar sirwolfgang avatar stve avatar twalpole avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wicked's Issues

Mongoid EMBEDDED 1-1 not working

Hello, thanks for this gem, it's awesome.

I've got little problem with Mongoid relation embedded 1-1. This 1-1 relation isn't building resource (current_order.build_address) in wicked controller. But when I try to build it in my (for example application) controller it is working as excepted.

My wizard controller:

class OrderController < ApplicationController
  include Wicked::Wizard

  steps :cart, :address, :shipping, :summary

  def show
    current_order.build_address
    render_wizard
  end
end

My Address model:

class Address
  include Mongoid::Document

  field :city

  embedded_in :order
end

My Order model:

class Order
  include Mongoid::Document

  embeds_one :address

  accepts_nested_attributes_for :address
end

Wicked form:

= form_for current_order, url: wizard_path do |f|
  = f.fields_for :address do |ff|
    = ff.text_field :city
  = f.submit

Redirect back to the last step

In my application user has to filled 7 steps for Visit model. But he can choose to exit from any step but if that user is coming back I want to show him what was his last step and redirect him there.

I tried to set a value for step but its not working

Handling instance variables

Hi,
I have a multi-step wizard with many instance variables per step (like 6-7 for each step, many of them options for dropdown selects). Is there a best practice to handle this variables? (considering I'll move to wicked to render the multi-step form)

Thanks in advance,

jump_to call ignored if render_wizard is called with resource

Hi,
first of all thanks for this great gem, it makes working with wizard really much easier.
When I'm using jump_to prior to using render_wizard(@resource), the @skip_to variable is overwritten, and the next step is rendered. This is expected behavior according to the README, but I think it would be better if render_wizard checks if @skip_to is set, and honors also when a resource is passed.

I'd be happy to put together a PR if you are interested.

Best regards,
Fabian

Dynamic Steps - undefined method `index' for nil:NilClass

This doesn't seem to work:

class SplitSharesController < ApplicationController
  include Wicked::Wizard

  before_filter :set_steps

  def show
   #snip
  end

  def update
   #snip
  end

  def finish_wizard_path
   #snip
  end

private
  def set_steps
    case params[:transaction_type]
    when 'split'
      steps = :split_details, :confirmation
    when 'consolidate'
      steps = :consolidate_details, :confirmation        
    end
  end
end

The error I get is:

NoMethodError in SplitSharesController#show

undefined method `index' for nil:NilClass

Any ideas on how to set the steps dynamically based on a url parameter? I want to encapsulate several similar transaction types in a single wizard as they share the same concern and would rather not have a ton of very similar wizard controllers.

Add skip_step into readme

Hello

Firstly, sorry if my english is a little bit wrong, and because I'm don't know anymore how to do a pull request, I'll write thing that could be upgrade

It could be great if skip_step is also referenced into Quick Reference - Controller Tidbits.

More, I would prefere to order Quick Reference as if we have
'View helper' (mainly the path helper) (already correct),
'Controller helper' (with render helper and skip helper) and
'Global helper' (with step and wizard_steps helper).

Personally, i was looking reference into that order.

Thanks

Stay on step if no field has input

Hey,

I'm trying wicked out and it has been great so far.
But my Rails/Ruby knowledge is letting me down right now and hopefully someone could help me here.

I have a little case in my update method.
At a certain step I want to check if there has been any valid input, if there isn't any input I want to stay on this step and don't go further.
Something along these lines:

def update
case step
when :order_articles
@order.add_amount_to_order_lines!(params[:order_lines])

  if [email protected]_valid_order_lines?
     #stay on the same step don't go further!
  end

end

render_wizard @order
end

Any idea how I can solve this problem?
Thanks a lot in advance

Niels

double redirect when wizard is finished

Hi again,
so I stumbled upon another 'issue'. When render_wizard is called with a resource when the last step is reached, a redirect occurs to /controller/finish, which issues another redirect to whatever is defined in finish_wizard_path. Is there any reason to do this? Would it make sense to directly redirect to whatever is defined in finish_wizard_path when the last step is reached?

In my case I need to redirect based on the resource, but it is 'lost' when the redirect to the finish step happens. I can think of several workarounds, but this double redirect seems unnecessary anyway.

What do you think?

Best regards,
Fabian

Forward params passed to the :finish step

The :finish step is redirecting to the show step but not forwarding the params that it needs.

def show
  @asset = Asset.find(params[:asset_id])
  @team = @asset.team
  render_wizard
end

Validations for Partial Objects

With sexy validations in Rails less redundant validations are possible.

validates :foo, :presence_on_step_or_active => {:step => :first}
def active?
    ...
end

# populate with current step in controller
attr_accessor :wicked_step 
class PresenceOnStepOrActiveValidator < ActiveModel::Validator
  def validate(record)
    if options[:step] == record.wicked_step || record.active?
      record.errors.add_on_blank(options[:attributes])
    end
  end
end

wicked_step could possibly be put in a more accessible place and be set in the setup_wizard before filter.

Dynamic steps

Feature request/advice

New rails developer here. Is it possible to dynamically define the wizard steps? I'm writing an interface for economics experiment, and I'd like to vary the order of the wizard based on the "type" of user visiting the controller. I don't think this would work (I'm not within an action with @user defined, don't know if I can do that outside an action):

  class FooController < ApplicationController
    include Wicked::Wizard

    if @user.type == 1
      steps :foo, :bar, :baz
    elsif @user.type ==2
      steps :bar, :baz, :foo

How would you approach this problem?

Inconsistency with step translations

When using the translation feature, you get a problematic inconsistency: while the step names in the steps array are translated, the name returned by step is the original name. This makes it a bit harder to to calculate progress and use the "case step" paradigm consistently etc..

It would be nice, if either both steps and step contained either the original (which I would prefer) or the translated step names.

Cheers
Michael

On interrupted Signups

Hey guys-

So i'm working on a site where I want users to be sent back to the sign-up step they're currently "on", while that's easy from within the wizard's controller, I'd like to interrupt other paths / pages pretty globally..using a before_filter in the app controller currently.

My current plan is to do something like:

redirect_to welcome_path(:step1) and return if current_user.steps_complete = 0
etc...

But that's pretty ugly, and the steps_complete method will be fragile. I wish welcome_path(:current_step) worked but it doesn't.. is there a smarter way to do this that I'm missing?

render_wizard extra param

Hi, I can not add an extra params to render_wizard method, in order to accomplish this i have

render_wizard(@channel, {:distributor_id => @distributor.id})

but I just redirect to the next step without the distributor_id params.
Have i anything wrong in my syntax?
Thank you

don't require inheriting from gem's controller

It would be better if using the gem didn't require inheriting from the gem's controller - Rails apps usually have an ApplicationController that contains lots of common configuration and helpers, and if you're not inheriting from that, you'll have to duplicate some of that code in the wizard controller.

Dynamic steps error

class ProfilesController < ApplicationController
  include Wicked::Wizard

  prepend_before_filter :set_my_steps

   def set_my_steps
     if !current_user.student?
       self.class.steps :foo, :bar, :baz
     else
       self.class.steps :bar, :baz, :foo
     end
   end

Don't work - says "undefined method `first' for nil:NilClass"

Error from: wicked (0.2.0) lib/wicked/wizard.rb:29:in `setup_wizard'

What it's can be? Thx

question: to pass an array of steps..

Thanks for your project! I realize this might involve metaprogramming, but I'm wonder if you happen to know if it's possible to pass an array of symbols to the steps method in a controller. e.g.:

PRODUCT_STEPS = [:step1, :step2, :step3]
steps PRODUCT_STEPS

Using next_wizard_path, previous_wizard_path etc but saving document in between

So I might not understand the process fully, but I like this solution for something I am working on. It is a wizard format questionnaire really that you can goto a page defined in wicked, complete some radio boxes (all that are in a form) save the document and it goes to the next step in the questionnaire. This is all working great, but I want the user to jump around ( I realize this breaks the wizard-ness of it but this is by far the best solution for what I am trying to do). So I have a nice header iwth three links:

HOME NEXT PREVIOUS
all using the next_wizard_path, previous_wizard_path and then the one that goes directly to home:
wizard_path(:doc_home)

this works great as well, the biggest issue I have though is it calls a show not an update so I cannot figure out how to take the current form items and save them to the db before going to the next_wizard_path, not even sure what direction id look into to do this...the green-ness of my rails is showing here but I am sure there has to be a way, i want to continue to use wicked as my solution this is the only thing perplexing me thus far.

update: render_wizard

is there a way to render back to the show step?

def update
  case step
  when :accept_terms
      if not params[:terms]
        ----> redirect to show step :accept_terms

?

render_wizard/redirect_to accept_terms path results in a redirect loop :-(

undefined method `include?'

I'm getting:

undefined method `include?' for nil:NilClass

Class User
  def active_or_address?
  status.include?('address') || active?
end

Full Trace

NoMethodError in RegistrationsController#create

undefined method `include?' for nil:NilClass
Rails.root: /Users/nelsonkeating/Desktop/remindeal1

Application Trace | Framework Trace | Full Trace
app/models/user.rb:54:in active_or_address?' /gems/activesupport-3.2.3/lib/active_support/callbacks.rb:524:in_run__4539920570864256223__validate__3874024522057665424__callbacks'
/gems/activesupport-3.2.3/lib/active_support/callbacks.rb:405:in __run_callback' /gems/activesupport-3.2.3/lib/active_support/callbacks.rb:385:in_run_validate_callbacks'
/gems/activesupport-3.2.3/lib/active_support/callbacks.rb:81:in run_callbacks' /gems/activemodel-3.2.3/lib/active_model/validations.rb:212:inrun_validations!'
/gems/activemodel-3.2.3/lib/active_model/validations/callbacks.rb:53:in block in run_validations!' /gems/activesupport-3.2.3/lib/active_support/callbacks.rb:425:in_run__4539920570864256223__validation__3874024522057665424__callbacks'
/gems/activesupport-3.2.3/lib/active_support/callbacks.rb:405:in __run_callback' /gems/activesupport-3.2.3/lib/active_support/callbacks.rb:385:in_run_validation_callbacks'
/gems/activesupport-3.2.3/lib/active_support/callbacks.rb:81:in run_callbacks' /gems/activemodel-3.2.3/lib/active_model/validations/callbacks.rb:53:inrun_validations!'
/gems/activemodel-3.2.3/lib/active_model/validations.rb:179:in valid?' /gems/activerecord-3.2.3/lib/active_record/validations.rb:69:invalid?'
/gems/activerecord-3.2.3/lib/active_record/validations.rb:77:in perform_validations' /gems/activerecord-3.2.3/lib/active_record/validations.rb:50:insave'
/gems/activerecord-3.2.3/lib/active_record/attribute_methods/dirty.rb:22:in save' /gems/activerecord-3.2.3/lib/active_record/transactions.rb:241:inblock (2 levels) in save'
/gems/activerecord-3.2.3/lib/active_record/transactions.rb:295:in block in with_transaction_returning_status' /gems/activerecord-3.2.3/lib/active_record/connection_adapters/abstract/database_statements.rb:192:intransaction'
/gems/activerecord-3.2.3/lib/active_record/transactions.rb:208:in transaction' /gems/newrelic_rpm-3.3.5/lib/new_relic/agent/method_tracer.rb:491:inblock in transaction_with_trace_ActiveRecord_self_name_transaction'
/gems/newrelic_rpm-3.3.5/lib/new_relic/agent/method_tracer.rb:242:in trace_execution_scoped' /gems/newrelic_rpm-3.3.5/lib/new_relic/agent/method_tracer.rb:486:intransaction_with_trace_ActiveRecord_self_name_transaction'
/gems/activerecord-3.2.3/lib/active_record/transactions.rb:293:in with_transaction_returning_status' /gems/activerecord-3.2.3/lib/active_record/transactions.rb:241:inblock in save'
/gems/activerecord-3.2.3/lib/active_record/transactions.rb:252:in rollback_active_record_state!' /gems/activerecord-3.2.3/lib/active_record/transactions.rb:240:insave'
/gems/devise-2.1.1/app/controllers/devise/registrations_controller.rb:15:in create' /gems/actionpack-3.2.3/lib/action_controller/metal/implicit_render.rb:4:insend_action'
/gems/actionpack-3.2.3/lib/abstract_controller/base.rb:167:in process_action' /gems/actionpack-3.2.3/lib/action_controller/metal/rendering.rb:10:inprocess_action'
/gems/actionpack-3.2.3/lib/abstract_controller/callbacks.rb:18:in block in process_action' /gems/activesupport-3.2.3/lib/active_support/callbacks.rb:447:in_run__3859976134561150154__process_action__1006715421838506127__callbacks'
/gems/activesupport-3.2.3/lib/active_support/callbacks.rb:405:in __run_callback' /gems/activesupport-3.2.3/lib/active_support/callbacks.rb:385:in_run_process_action_callbacks'
/gems/activesupport-3.2.3/lib/active_support/callbacks.rb:81:in run_callbacks' /gems/actionpack-3.2.3/lib/abstract_controller/callbacks.rb:17:inprocess_action'
/gems/actionpack-3.2.3/lib/action_controller/metal/rescue.rb:29:in process_action' /gems/actionpack-3.2.3/lib/action_controller/metal/instrumentation.rb:30:inblock in process_action'
/gems/activesupport-3.2.3/lib/active_support/notifications.rb:123:in block in instrument' /gems/activesupport-3.2.3/lib/active_support/notifications/instrumenter.rb:20:ininstrument'
/gems/activesupport-3.2.3/lib/active_support/notifications.rb:123:in instrument' /gems/actionpack-3.2.3/lib/action_controller/metal/instrumentation.rb:29:inprocess_action'
/gems/actionpack-3.2.3/lib/action_controller/metal/params_wrapper.rb:205:in process_action' /gems/activerecord-3.2.3/lib/active_record/railties/controller_runtime.rb:18:inprocess_action'
/gems/newrelic_rpm-3.3.5/lib/new_relic/agent/instrumentation/rails3/action_controller.rb:34:in block in process_action' /gems/newrelic_rpm-3.3.5/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:257:inblock in perform_action_with_newrelic_trace'
/gems/newrelic_rpm-3.3.5/lib/new_relic/agent/method_tracer.rb:242:in trace_execution_scoped' /gems/newrelic_rpm-3.3.5/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:252:inperform_action_with_newrelic_trace'
/gems/newrelic_rpm-3.3.5/lib/new_relic/agent/instrumentation/rails3/action_controller.rb:33:in process_action' /gems/actionpack-3.2.3/lib/abstract_controller/base.rb:121:inprocess'
/gems/actionpack-3.2.3/lib/abstract_controller/rendering.rb:45:in process' /gems/actionpack-3.2.3/lib/action_controller/metal.rb:203:indispatch'
/gems/actionpack-3.2.3/lib/action_controller/metal/rack_delegation.rb:14:in dispatch' /gems/actionpack-3.2.3/lib/action_controller/metal.rb:246:inblock in action'
/gems/actionpack-3.2.3/lib/action_dispatch/routing/route_set.rb:73:in call' /gems/actionpack-3.2.3/lib/action_dispatch/routing/route_set.rb:73:indispatch'
/gems/actionpack-3.2.3/lib/action_dispatch/routing/route_set.rb:36:in call' /gems/actionpack-3.2.3/lib/action_dispatch/routing/mapper.rb:40:incall'
/gems/journey-1.0.4/lib/journey/router.rb:68:in block in call' /gems/journey-1.0.4/lib/journey/router.rb:56:ineach'
/gems/journey-1.0.4/lib/journey/router.rb:56:in call' /gems/actionpack-3.2.3/lib/action_dispatch/routing/route_set.rb:600:incall'
/gems/sass-3.1.19/lib/sass/plugin/rack.rb:54:in call' /gems/newrelic_rpm-3.3.5/lib/new_relic/rack/browser_monitoring.rb:12:incall'
/gems/newrelic_rpm-3.3.5/lib/new_relic/rack/developer_mode.rb:24:in call' /gems/client_side_validations-3.1.4/lib/client_side_validations/middleware.rb:18:incall'
/gems/warden-1.2.1/lib/warden/manager.rb:35:in block in call' /gems/warden-1.2.1/lib/warden/manager.rb:34:incatch'
/gems/warden-1.2.1/lib/warden/manager.rb:34:in call' /gems/actionpack-3.2.3/lib/action_dispatch/middleware/best_standards_support.rb:17:incall'
/gems/rack-1.4.1/lib/rack/etag.rb:23:in call' /gems/rack-1.4.1/lib/rack/conditionalget.rb:35:incall'
/gems/actionpack-3.2.3/lib/action_dispatch/middleware/head.rb:14:in call' /gems/actionpack-3.2.3/lib/action_dispatch/middleware/params_parser.rb:21:incall'
/gems/actionpack-3.2.3/lib/action_dispatch/middleware/flash.rb:242:in call' /gems/rack-1.4.1/lib/rack/session/abstract/id.rb:205:incontext'
/gems/rack-1.4.1/lib/rack/session/abstract/id.rb:200:in call' /gems/actionpack-3.2.3/lib/action_dispatch/middleware/cookies.rb:338:incall'
/gems/activerecord-3.2.3/lib/active_record/query_cache.rb:64:in call' /gems/activerecord-3.2.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:467:incall'
/gems/actionpack-3.2.3/lib/action_dispatch/middleware/callbacks.rb:28:in block in call' /gems/activesupport-3.2.3/lib/active_support/callbacks.rb:405:in_run__1050537933734709659__call__3874024522057665424__callbacks'
/gems/activesupport-3.2.3/lib/active_support/callbacks.rb:405:in __run_callback' /gems/activesupport-3.2.3/lib/active_support/callbacks.rb:385:in_run_call_callbacks'
/gems/activesupport-3.2.3/lib/active_support/callbacks.rb:81:in run_callbacks' /gems/actionpack-3.2.3/lib/action_dispatch/middleware/callbacks.rb:27:incall'
/gems/actionpack-3.2.3/lib/action_dispatch/middleware/reloader.rb:65:in call' /gems/actionpack-3.2.3/lib/action_dispatch/middleware/remote_ip.rb:31:incall'
/gems/actionpack-3.2.3/lib/action_dispatch/middleware/debug_exceptions.rb:16:in call' /gems/actionpack-3.2.3/lib/action_dispatch/middleware/show_exceptions.rb:56:incall'
/gems/railties-3.2.3/lib/rails/rack/logger.rb:26:in call_app' /gems/railties-3.2.3/lib/rails/rack/logger.rb:16:incall'
/gems/actionpack-3.2.3/lib/action_dispatch/middleware/request_id.rb:22:in call' /gems/rack-1.4.1/lib/rack/methodoverride.rb:21:incall'
/gems/rack-1.4.1/lib/rack/runtime.rb:17:in call' /gems/activesupport-3.2.3/lib/active_support/cache/strategy/local_cache.rb:72:incall'
/gems/rack-1.4.1/lib/rack/lock.rb:15:in call' /gems/actionpack-3.2.3/lib/action_dispatch/middleware/static.rb:62:incall'
/gems/railties-3.2.3/lib/rails/engine.rb:479:in call' /gems/railties-3.2.3/lib/rails/application.rb:220:incall'
/gems/rack-1.4.1/lib/rack/content_length.rb:14:in call' /gems/railties-3.2.3/lib/rails/rack/log_tailer.rb:14:incall'
/gems/thin-1.3.1/lib/thin/connection.rb:80:in block in pre_process' /gems/thin-1.3.1/lib/thin/connection.rb:78:incatch'
/gems/thin-1.3.1/lib/thin/connection.rb:78:in pre_process' /gems/thin-1.3.1/lib/thin/connection.rb:53:inprocess'
/gems/thin-1.3.1/lib/thin/connection.rb:38:in receive_data' /gems/eventmachine-0.12.10/lib/eventmachine.rb:256:inrun_machine'
/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in run' /gems/thin-1.3.1/lib/thin/backends/base.rb:61:instart'
/gems/thin-1.3.1/lib/thin/server.rb:159:in start' /gems/rack-1.4.1/lib/rack/handler/thin.rb:13:inrun'
/gems/rack-1.4.1/lib/rack/server.rb:265:in start' /gems/railties-3.2.3/lib/rails/commands/server.rb:70:instart'
/gems/railties-3.2.3/lib/rails/commands.rb:55:in block in ' /gems/railties-3.2.3/lib/rails/commands.rb:50:intap'
/gems/railties-3.2.3/lib/rails/commands.rb:50:in ' script/rails:6:inrequire'
script/rails:6:in `'

redirect_to_finish_wizard

Hey, great gem and it works great for me, too.

I do not want to redirect to root_url and thus would like to use the
def redirect_to_finish_wizard. I copied it from the example but unfortunately it throws me an error:

wrong number of arguments (1 for 0)
app/controllers/event_steps_controller.rb:18:in redirect_to_finish_wizard' app/controllers/event_steps_controller.rb:7:inshow'
{"id"=>"finish"}

I am pretty sure it has nothing to do with the gem but for the moment I am really stuck. So, thx for any help.

wizard for remote forms

I use wicked gem in a situation where I use remote form for both the create action and for the other steps in the wizard
I cannot figure out how to make remote forms work in this context

I have the steps steps :course_description, :targeted_groups, :sub_targets
I am using new.js for the first step that uses the controller courses_controller and have tried targeted_groups,js loading the partial _targeted_groups.html for the second step using courses_wizard_controllerand.
I have also tried show.js loading the same partial but both these attemps failed.

How to use wicked with remote forms?
Is it possible ?
Is there any workaround if not ?

uninitialized constant Wicked::Wizard

Getting the following error when using a namespaced controller.

uninitialized constant Wicked::Wizard

The following makes no difference either:
::Wicked::Wizard

Rails 4 compatibility

I started a Rails 4 app and attempted to integrate wicked. Rails appears to be looking for a "show" template instead of the template with the step name.

I'm in a namespaced controller which i haven't used with wicked before, so potentially that is the issue instead, but the Rails 4 upgrade seemed more likely

#routes.rb
  namespace :profiles do
    resources :setup
  end
# app/controllers/profiles/setup_controller
class Profiles::SetupController < ApplicationController
  include Wicked::Wizard
  steps :bio

  def show
  end

  def edit
  end
end
#error
ActionView::MissingTemplate (Missing template profiles/setup/show, application/show with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :raw, :ruby, :coffee]}.

previous_wizard_path not recognized

Hi - awesome project. Thank you.

Everything works except for this one feature. The system doesn't have it defined. My workaround is to use wizard_path() with the step explicitly given.

wizard_path doesn't do anything useful for unsaved records

I'm trying to do a wizard for creating a new entry (profile) in an app where one user has many profiles.

    # Migration
    create_table :profiles do |t|

      t.integer :user_id,    null: false
      t.string  :name,       null: false, limit: 100

      t.boolean :visible,    null: false, default: false

      t.integer :age
      t.integer :height
      t.integer :weight

   end

I have migrations akin to those you recommend in the blog post about multi-step form validation, which I imagine works quite well, however the problem is:

<form accept-charset="UTF-8" action="/assets?action=show&amp;controller=profile" class="form-horizontal" id="new_profile" method="post">

This doesn't seem to be related to whether the model is saved or not, and I'm having a hard time to understand what I might be doing wrong.

= form_for profile, url: wizard_path, html: {class: 'form-horizontal'} do |f|
  = h profile.inspect
  %fieldset
    = yield f

Note: Opening as a bug, because whatever I'm doing is non-obvious and I'd expect an exception if I've done something that wizard_path doesn't understand.

Creating POST routes for wicked

(Apologies in advance, this is more a question than a bug)

I have created a 'widget' using Wicked that I'm trying to use in a Facebook Canvas App.

Facebook calls the specified URL with POST as opposed to GET, so it searches for an action with the name of the 'step' instead of the show action, resulting in a 500 error.

Can you think of a workaround for this?

I'm thinking I might be able to create an action for each step name, and redirect as appropriate, but that'd be pretty ugly.

Thanks for the great gem!

302 Moved Temporarily response from ajax form

Hi there,

I'm wondering if you can help me, I'm using your Wicked gem and sending the form via AJAX, but always seem to get the response: 302 Moved Temporarily, in our controller we've got:

format.html { redirect_to project_step_path("todos") }
format.js { redirect_to project_step_path("todos") }
format.json { redirect_to project_step_path("todos") }

"todos" being the first step of the wizard.

It does work perfectly without ajax.

It looks to me as if the response never gets to the project_steps_controller

If you are able to help, that'll be great :D

cheers
CHRXS

save method called twice

In the example you provide:

class AfterSignupController < ApplicationController
  include Wicked::Wizard

  steps :confirm_password, :confirm_profile, :find_friends

  def update
    @user = current_user
    case step
    when :confirm_password
      @user.update_attributes(params[:user])
    end
    sign_in(@user, :bypass => true) # needed for devise
    render_wizard @user
  end
end

On the confirm_password step, you are calling update_attributes which is calling the save method on the user.
Then, in render_wizard @user, the process_resource! method is being called on the user resource, which also calls the save method.

As a consequence, it looks like 2 transactions are being made and model callbacks are being called twice.

Any idea if I am doing something stupid or what should be done to avoid having callbacks called twice?

Thanks!

blocking non-relevant fields in a step

Ok, I don't know if you have an easy solution for this situation:
Let's say I have something like this with two steps defined in my controller:
where, e.g: I validate fieldA if I'm on stepA and I validate fieldB if I'm on stepB (you could imagine I do the same pattern for C,D, etc..)

class Products::BuildController < PrivateController
    steps :stepA, :stepB, stepC, stepD
end


class Product < ActiveRecord::Base
  validates :fieldA, :inclusion => {:in => 0..10}, :if => :active_or_on_stepA?
  validates :fieldB, :inclusion => {:in => 11..20}, :if => :active_or_on_stepB?

  def active?
    self.status == "active"
  end

  def active_or_on_stepA?
    self.status == "stepA" || active?
  end

  def active_or_on_stepB?
    self.status == "stepB" || active?
  end
end

ok, now let's say (evil) hacker, Mallory is able to inject fieldA to step B. (and saves an evil value for fieldA :)). Mallory then submits the rogue value in stepB.. (maybe storing -100 for fieldA in stepB).
.. then the database would store the updated/rogue fieldA when the user is e.g: then on stepC.

I wonder if you know a good way to stop that from happening. (I realize that moving to the active state would eventually fail/die but e.g: while stepC and stepD are occurring, corrupted values could be in the database).

Any ideas on this? Thanks!

Routing error when wicked controllers are namespaced.

Whenever I try to namespace my wicked controllers I always get routing errors, and can't seem to find any documentation regarding how one would pull it off.

My routes.rb looks like this:

resources :setup, controller: 'Wizards::AfterSignup'

But always the error

No route matches {:controller=>"wizards/after_signup", :action=>"show", :id=>"subscription"}

A mistake in a wizard_value method

In lib/wicked/wizard/translated.rb there is such method:

def wizard_value(step_name)
    wizard_translations[step]
end

As u see wizard_translations take step and not step_name as argument.
Correct implementation is

def wizard_value(step_name)
  wizard_translations[step_name]
end

Pls fix it

Set custom layout for render_wizard

How can i set a custom layout for the wizard steps?

i don't want to use the application.html.erb layout, so i create another, but how can i tell to render_wizard to use the new layout?

Wizard paths with object IDs

I'm not sure how to use Wicked with paths like:

/controller/:id/wizard_step

The situation is that I want to create a new product:

/products/new

Save a new object and redirect to the wizard to populate its data:

/products/1/step_1
/products/1/step_2
etc.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.