Validation groups for wizard-style forms
-
09-09-2019 - |
Question
can somebody explain me, how to do wizard-style forms with validations?
f.e.:
i have a appointment-model, which should include following data: name, starttime, endtime, address, city.
Now i want to have 3 actions for each datagroup:
- name
- start and enddate
- address-fields
each of them should be accessible (so AASM isn't an option I think -> model.wizard_step = 3 and generating the right view for this step isnt enough).
And each of them should have validations
- name shouldnt be nil
- startdate must not be after enddate
- addressfields must not be nil
but how do i save this object between the single steps, and how to build in this validations schemas/groups...?
heeelp.. thanks =)
Solution
You could use the Grouped Validations gem for this: https://github.com/adzap/grouped_validations
OTHER TIPS
Combine a hidden field in your form:
f.hidden_field :wizard_stage, :value => '<current action>'
with something like this
class Appointment < ActiveRecord::base
attr_accessor :wizard_stage
validates_presence_of :name, :if => lambda{|a| a.wizard_stage == 'name'}
validates_presence_of [:start, :end], :if => lambda{|a| a.wizard_stage = 'dates'}
end
You're going to have to basically "roll your own" on this one. The closest you can get with standard Rails / ActiveRecord functionality is to do something like the following:
class WizardController < ApplicationController
def wizard_1
foo = Foo.new params[:foo]
foo.valid?
if %{name}.any? {|att| foo.errors.on(att) }
# failed pseudo-validation
else
render :wizard_2
end
end
def wizard_2
foo = Foo.new params[:foo]
foo.valid?
if %{name startdate enddate}.any? {|att| foo.errors.on(att) }
# failed pseudo-validation
else
render :wizard_3
end
end
def wizard_3
# standard rails Controller#create
end
end
And you'll have to pass along the variables from each step into hidden fields in the next. You might also want to consider simply doing this in one stage, rather than in three.
can't you just use :if ?
e.g.
validates_presence_of :name
validates_presence_of :address_fields, :if => Proc.new {|p| p.startdate && p.enddate}
def validate
unless name.blank?
errors.add(:startdate) if startdate > enddate
end
end