[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7908":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":16,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":10,"pushedAt":10,"updatedAt":23,"readmeContent":24,"aiSummary":25,"trendingCount":16,"starSnapshotCount":16,"syncStatus":26,"lastSyncTime":27,"discoverSource":28},7908,"wicked","zombocom\u002Fwicked","zombocom","Use wicked to turn your controller into a wizard","http:\u002F\u002Fschneems.com",null,"Ruby",2859,190,43,13,0,28.84,"MIT License",false,"main",true,[],"2026-06-12 02:01:46","![](.\u002Fwicked.png)\n\n# Step-By-Step Wizard Controllers\n\n[![Build Status](https:\u002F\u002Fgithub.com\u002Fzombocom\u002Fwicked\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg?branch=main)](https:\u002F\u002Fgithub.com\u002Fzombocom\u002Fwicked)\n[![Code Climate](https:\u002F\u002Fcodeclimate.com\u002Fgithub\u002Fschneems\u002Fwicked\u002Fbadges\u002Fgpa.svg)](https:\u002F\u002Fcodeclimate.com\u002Fgithub\u002Fschneems\u002Fwicked)\n[![Help Contribute to Open Source](https:\u002F\u002Fwww.codetriage.com\u002Fschneems\u002Fwicked\u002Fbadges\u002Fusers.svg)](https:\u002F\u002Fwww.codetriage.com\u002Fschneems\u002Fwicked)\n\n\nUse wicked to make your Rails controllers into step-by-step wizards. To see Wicked in action check out the example [Rails app](https:\u002F\u002Fgithub.com\u002Fschneems\u002Fwicked_example) or [watch the screencast](http:\u002F\u002Fschneems.com\u002Fpost\u002F18437886598\u002Fwizard-ify-your-rails-controllers-with-wicked).\n\n## Why\n\nMany 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.\n\n## Install\n\nAdd this to your Gemfile\n\n```ruby\ngem 'wicked'\n```\n\nThen run `bundle install` and you're ready to start\n\n## Quicklinks\n\n* [Build an object step-by-step](https:\u002F\u002Fgithub.com\u002Fschneems\u002Fwicked\u002Fwiki\u002FBuilding-Partial-Objects-Step-by-Step)\n* [Use object ID's with wizard paths](https:\u002F\u002Fgithub.com\u002Fschneems\u002Fwicked\u002Fwiki\u002FBuilding-Partial-Objects-Step-by-Step)\n* [Show Current Wizard Progress to User](https:\u002F\u002Fgithub.com\u002Fschneems\u002Fwicked\u002Fwiki\u002FShow-Current-Wizard-Progress-to-User)\n* [Example App](https:\u002F\u002Fgithub.com\u002Fschneems\u002Fwicked_example)\n* [Screencast](http:\u002F\u002Fschneems.com\u002Fpost\u002F18437886598\u002Fwizard-ify-your-rails-controllers-with-wicked)\n* [Devise Onboarding With Wicked by Deanin](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=P-eYHvgT4KA)\n* [Watch Railscasts episode: #346 Wizard Forms with Wicked](http:\u002F\u002Frailscasts.com\u002Fepisodes\u002F346-wizard-forms-with-wicked)\n\n## How\n\nWe 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](https:\u002F\u002Fgithub.com\u002Fschneems\u002Fwicked\u002Fwiki\u002FBuilding-Partial-Objects-Step-by-Step).\n\nFirst create a controller:\n\n```\nrails g controller after_signup\n```\n\nAdd Routes into `config\u002Froutes.rb`:\n\n```ruby\nresources :after_signup\n```\n\nNext include `Wicked::Wizard` in your controller\n\n```ruby\n\nclass AfterSignupController \u003C ApplicationController\n  include Wicked::Wizard\n\n  steps :confirm_password, :confirm_profile, :find_friends\n  # ...\n\n```\n\nYou can also use the old way of inheriting from `Wicked::WizardController`.\n\n```ruby\n\nclass AfterSignupController \u003C Wicked::WizardController\n\n  steps :confirm_password, :confirm_profile, :find_friends\n  # ...\n\n```\n\nThe 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)`.\n\n```ruby\nclass AfterSignupController \u003C ApplicationController\n  include Wicked::Wizard\n\n  steps :confirm_password, :confirm_profile, :find_friends\n\n  def show\n    @user = current_user\n    case step\n    when :find_friends\n      @friends = @user.find_friends\n    end\n    render_wizard\n  end\nend\n```\n\n**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:\u002F\u002Fgithub.com\u002Fschneems\u002Fwicked\u002Fwiki\u002FBuilding-Partial-Objects-Step-by-Step) for an example. It will need to be prefixed, for example a Product's `:id` would be `:product_id`\n\nYou'll need to call `render_wizard` at the end of your action to get the correct views to show up.\n\nBy default the wizard will render a view with the same name as the step. So for our controller `AfterSignupController` with a view path of `\u002Fviews\u002Fafter_signup\u002F` if call the :confirm_password step, our wizard will render `\u002Fviews\u002Fafter_signup\u002Fconfirm_password.html.erb`\n\nThen in your view you can use the helpers to get to the next step.\n\n```erb\n\u003C%= link_to 'skip', next_wizard_path %>\n```\n\nYou can manually specify which wizard action you want to link to by using the wizard_path helper.\n\n```erb\n\u003C%= link_to 'skip', wizard_path(:find_friends) %>\n```\n\nIn addition to showing sequential views we can update elements in our controller.\n\n\n```ruby\nclass AfterSignupController \u003C ApplicationController\n  include Wicked::Wizard\n\n  steps :confirm_password, :confirm_profile, :find_friends\n\n  def update\n    @user = current_user\n    case step\n    when :confirm_password\n      @user.update(user_params)\n    end\n    sign_in(@user, bypass: true) # needed for devise\n    render_wizard @user\n  end\n  \n  private\n  def user_params\n    params.require(:user)\n          .permit(:email, :current_password) # ...\n  end\nend\n```\n\nWe'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.\n\nNote 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.\n\nTo get to this update action, you simply need to submit a form that PUT's to the same url\n\n```erb\n\u003C%= form_for @user, url: wizard_path, method: :put do |f| %>\n  \u003C%=  f.password_field :password  %>\n  \u003C%=  f.password_field :password_confirmation  %>\n\n  \u003C%= f.submit \"Change Password\" %>\n\u003C% end %>\n```\n\nWe 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.\n\n\nIn the controller if you find that you want to skip a step, you can do it simply by calling `skip_step`\n\n```ruby\ndef show\n  @user = current_user\n  case step\n  when :find_friends\n    if @user.has_facebook_access_token?\n      @friends = @user.find_friends\n    else\n      skip_step\n    end\n  end\n  render_wizard\nend\n```\n\nNow you've got a fully functioning AfterSignup controller! If you have questions or if you struggled with something, let me know on [twitter](http:\u002F\u002Ftwitter.com\u002Fschneems), and i'll try to make it better or make the docs better.\n\n## Quick Reference\n\n**View\u002FURL Helpers:**\n\n```ruby\nwizard_path                  # relative url of the current step\nwizard_path(:specific_step)  # relative url of a :specific_step\nnext_wizard_path             # relative url of the next step\nprevious_wizard_path         # relative url of the previous step\n\nwizard_url                  # fully qualified url of the current step\nwizard_url(:specific_step)  # fully qualified url of a :specific_step\nnext_wizard_url             # fully qualified url of the next step\nprevious_wizard_url         # fully qualified url of the previous step\n\n# These only work while in a Wizard\n# You can have multiple wizards in a project with multiple `wizard_path` calls\n```\n\n\n**Controller Tidbits:**\n\n```ruby\nsteps  :first, :second                        # Sets the order of steps\nstep                                          # Gets current step\nnext_step                                     # Gets next step\nprevious_step                                 # Gets previous step\nskip_step                                     # Tells render_wizard to skip to the next logical step\njump_to(:specific_step)                       # Jump to :specific_step\nrender_wizard                                 # Renders the current step\nrender_wizard(@user)                          # Shows next_step if @user.save, otherwise renders\nrender_wizard(@user, context: :account_setup) # Shows next_step if @user.save(context: :account_setup), otherwise renders\nwizard_steps                                  # Gets ordered list of steps\ncurrent_step?(step)                           # is step the same as the current request's step\npast_step?(step)                              # does step come before the current request's step in wizard_steps\nfuture_step?(step)                            # does step come after the current request's step in wizard_steps\nprevious_step?(step)                          # is step immediately before the current request's step\nnext_step?(step)                              # is step immediately after the current request's step\n```\n\n**Redirect options**\n\nBoth `skip_step` and `jump_to` will cause a redirect.\n\n```\nskip_step(foo: \"bar\")\n```\n\n*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.*\n\nIf you want to pass params to the step you are skipping to you can pass it into those:\n\n```\njump_to(:specific_step, foo: \"bar\")\n```\n\n**Finally:**\n\nDon't forget to create your named views\n\n```\napp\u002F\n  views\u002F\n    controller_name\u002F\n      first.html.erb\n      second.html.erb\n      # ...\n```\n\n\n## Finish Wizard Path\n\nYou can specify the url that your user goes to by over-riding the `finish_wizard_path` in your wizard controller.\n\n\n```ruby\ndef finish_wizard_path\n  user_path(current_user)\nend\n```\n\n### Testing with RSpec\n\n```ruby\n# Test find_friends block of show action\nget :show, params: { id: :find_friends }\n\n# Test find_friends block of update action\npatch :update, params: {'id' => 'find_friends', \"user\" => { \"id\" => @user.id.to_s }}\n```\n\n### Internationalization of URLS (I18n)\n\nIf 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:\n\n```ruby\ninclude Wicked::Wizard\n```\n\nWith this:\n\n```ruby\ninclude Wicked::Wizard::Translated\n```\n\nThis will allow you to specify translation keys instead of literal step names. Let's say you've got steps that look like this:\n\n    steps :first, :second\n\nSo the urls would be `\u002Fafter_signup\u002Ffirst` and `\u002Fafter_signup\u002Fsecond`. But you want them to show up differently for different locales. For example someone coming form a Spanish speaking locale should see `\u002Fafter_signup\u002Funo` and `after_signup\u002Fdos`.\n\nTo internationalize first you need to create your locales files under `config\u002Flocales` such as `config\u002Flocales\u002Fes.yml` for Spanish. You then need to add a `first` and `second` key under a `wicked` key like this:\n\n```yaml\nes:\n  hello: \"hola mundo\"\n  wicked:\n    first: \"uno\"\n    second: \"dos\"\n```\n\nIt would also be a good idea to create a english version under `config\u002Flocales\u002Fen.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\n\n```ruby\nbefore_action :set_locale\n\nprivate\n\ndef set_locale\n  I18n.locale = params[:locale] if params[:locale].present?\nend\n\ndef default_url_options(options = {})\n  {locale: I18n.locale}\nend\n```\n\nFor a screencast on setting up and using I18n check out [Railscasts](http:\u002F\u002Frailscasts.com\u002Fepisodes\u002F138-i18n-revised). You can also read the [free I18n Rails Guide](http:\u002F\u002Fguides.rubyonrails.org\u002Fi18n.html).\n\nNow when you visit your controller with the proper locale set your URLs should be more readable like `\u002Fafter_signup\u002Funo` and `after_signup\u002Fdos`.\n\nWicked expects your files to be named the same as your keys, so when a user visits `after_signup\u002Fdos` with the `es` locale it will render the `second.html.erb` file.\n\n\n**Important:** When you do this the value of `step` as well as\n`next_step` and `previous_step` and all the values within `steps` will\nbe translated to what locale you are using. To translate them to the\n\"canonical\" values that you've have in your controller you'll need so\nuse `wizard_value` method.\n\nFor example, if you had this in your controller, and you converted it to\na use Wicked translations, so this will not work:\n\n```ruby\nsteps :confirm_password, :confirm_profile, :find_friends\n\ndef show\n  case step\n  when :find_friends\n    @friends = current_user.find_friends\n  end\n  render_wizard\nend\n```\n\nInstead you need to use `wizard_value` to get the \"reverse translation\" in your controller code like this:\n\n```ruby\nsteps :confirm_password, :confirm_profile, :find_friends\n\ndef show\n  case wizard_value(step)\n  when :find_friends\n    @friends = current_user.find_friends\n  end\n  render_wizard\nend\n```\n\nThe important thing to remember is that `step` and the values in `steps` are\nalways going to be in the same language if you're using the Wicked translations.\nIf you need any values to match the values set directly in your controller,\n or the names of your files (i.e. `views\u002F..\u002Fconfirm_password.html.erb`, then you need\nto use `wizard_value` method.\n\n## Custom URLs\n\nVery 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:\n\n```ruby\ninclude Wicked::Wizard::Translated\n```\n\nThen 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\u002Flocales\u002Fen.yml`\n\n```yaml\nen:\n  hello: \"hello world\"\n  wicked:\n    first: \"verify_email\"\n    second: \"if_you_are_popular_add_friends\"\n```\n\nNow 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\u002Fapplication.rb` file.\n\n```ruby\nconfig.i18n.default_locale = :de\n```\n\n**Important:** Don't forget to use `wizard_value()` method to make\nsure you are using the right canonical values of `step`,\n`previous_step`, `next_step`, etc. If you are comparing them to non\nwicked generate values.\n\nCustom crafted wizard urls: just another way Wicked makes your app a little more saintly.\n\n## Dynamic Step Names\n\nIf you wish to set the order of your steps dynamically you can do this by manually calling  and `self.steps = [# \u003Csome steps> ]` in a `before_action` method. Then call `before_action :setup_wizard` after so that wicked knows when it is safe to initializelike this:\n\n```ruby\ninclude Wicked::Wizard\nbefore_action :set_steps\nbefore_action :setup_wizard\n\n# ...\n\nprivate\ndef set_steps\n  if params[:flow] == \"twitter\"\n    self.steps = [:ask_twitter, :ask_email]\n  elsif params[:flow] == \"facebook\"\n    self.steps = [:ask_facebook, :ask_email]\n  end\nend\n```\n\nNOTE: 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.\n\n## Send params to finish_wizard_path method\n\nIf 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`.\n\nIn order to send the parameters to the method here is an example of the show method:\n\n```ruby\nsteps :first_step, :second_step\n\ndef show\n  # ...\n  render_wizard(nil, {}, { hello: 'world' })\nend\n\ndef update\n  # ...\n  render_wizard(@user, {}, { hello: 'world' })\nend\n\ndef finish_wizard_path(params)\n  # here you can access params and that would be equal to { hello: 'world' }\nend\n```\n\nThe `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:\n\n```ruby\nnext_wizard_path({ hello: 'world' })\nwizard_path(nil, { hello: 'world' })\n# the wizard_path with the step specified would look like this\nwizard_path(:wicked_finish, wizard_id: @user.id, hello: 'world')\n```\n\n## Keywords\n\nThere are a few \"magical\" keywords that will take you to the first step,\nthe last step, or the \"final\" action (the redirect that happens after\nthe last step). Prior to version 0.6.0 these were hardcoded strings. Now\nthey are constants which means you can access them or change them. They\nare:\n\n```ruby\nWicked::FIRST_STEP\nWicked::LAST_STEP\nWicked::FINISH_STEP\n```\n\nYou can build links using these constants\n`after_signup_path(Wicked::FIRST_STEP)` which will redirect the user to\nthe first step you've specified. This might be useful for redirecting a\nuser to a step when you're not already in a Wicked controller. If you\nchange the constants, they are expected to be strings (not symbols).\n\n## Support\n\nMost problems using this library are general problems using Ruby\u002FRails. If you cannot get something to work correctly please open up a question on [stack overflow](http:\u002F\u002Fstackoverflow.com\u002F). 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.\n\nIf you've found a bug, please open a ticket on the issue tracker with a small example app that reproduces the behavior.\n\n## About\n\nMade by [@schneems](http:\u002F\u002Ftwitter.com\u002Fschneems).\n\nThis project rocks and uses MIT-LICENSE.\n\n## Compatibility\n\nRefer 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.\n\nNote: Rails 3.0 support is only for Ruby 1.9.3 or JRuby, not Ruby 2.0.0 or newer.\n\n## Running Gem Tests\n\nFirst, install the development gems:\n\n```\n$ bundle install\n```\n\nNow that `appraisal` is installed, use it to set up all the gemfiles for the test matrix:\n\n```\n$ appraisal install\n```\n\nThen to run tests against all the appraisal gemfiles, use:\n\n```\n$ appraisal rake test\n```\n\nTo run tests against one specific gemfile,\nuse\n\n```\n$ appraisal 4.1 rake test\n```\n\nNote 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\ngemfile if you are using a current version of Ruby.\n\n## Contributing\n\nSee the [Contributing guide](https:\u002F\u002Fgithub.com\u002Fschneems\u002Fwicked\u002Fblob\u002Fmaster\u002FCONTRIBUTING.md).\n","Wicked 是一个用于将 Rails 控制器转换为分步向导的 Ruby 库。它通过提供简洁的 API 和灵活的配置，使得开发者可以轻松地创建多步骤表单或流程，而无需处理复杂的会话管理和状态跟踪。Wicked 支持定义步骤、自定义逻辑以及与现有资源的集成，特别适合需要用户按顺序完成多个操作的应用场景，如注册流程、复杂表单填写等。MIT 许可证下开源，拥有活跃的社区支持和详细的文档指导，便于快速上手和扩展。",2,"2026-06-11 03:15:02","top_language"]