patternrubyrailsMinor
Refactoring multistep form rails
Viewed 0 times
refactoringformrailsmultistep
Problem
I've implemented just as Ryan Bates suggested in his railscast episode, I've got everything working just right, so here is his approach in the controller :
I'm ok with new method, but I wonder how can the create method be refactored. He said that he will do an episode how to refactor this in the future but he did not yet.
This was my take on he reactoring (more splitting than refactoring):
def new
session[:order_params] ||= {}
@order = Order.new(session[:order_params])
@order.current_step = session[:order_step]
end
def create
session[:order_params].deep_merge!(params[:order]) if params[:order]
@order = Order.new(session[:order_params])
@order.current_step = session[:order_step]
if @order.valid?
if params[:back_button]
@order.previous_step
elsif @order.last_step?
@order.save if @order.all_valid?
else
@order.next_step
end
session[:order_step] = @order.current_step
end
if @order.new_record?
render "new"
else
session[:order_step] = session[:order_params] = nil
flash[:notice] = "Order saved!"
redirect_to @order
end
endI'm ok with new method, but I wonder how can the create method be refactored. He said that he will do an episode how to refactor this in the future but he did not yet.
This was my take on he reactoring (more splitting than refactoring):
def create
session[:order_params].deep_merge!(params[:order]) if params[:order]
@order = Order.new(session[:order_params])
@order.current_step = session[:order_step]
process_step
if @order.new_record?
render "new"
else
session[:order_step] = session[:order_params] = nil
flash[:notice] = "Order saved!"
redirect_to @order
end
end
def process_step
if @order.valid?
if params[:back_button]
@order.previous_step
elsif @order.last_step?
@order.save if @order.all_valid?
else
@order.next_step
end
session[:order_step] = @order.current_step
end
endSolution
I would advise you to look at wicked gem: https://github.com/schneems/wicked.
Using this gem you could write:
It will also separate your forms for each step. To add any step-related action you can use
Using this gem you could write:
include Wicked::Wizard
steps
def new
session[:order_id] ||= Order.create.id
end
def show
@order = Order.find(session[:order_id])
end
def update
@order = Order.find(session[:order_id])
@order.assign_attributes(params[:order_params])
@order.current_step = step
render_wizard @order
endIt will also separate your forms for each step. To add any step-related action you can use
step reader:def update
@order = Order.find(session[:order_id])
@order.assign_attributes(params[:order_params])
@order.current_step = step
@order.do_sth if step == :my_step
render_wizard @order
endrender_wizard automatically tries to save an object and redirects you to the next step or renders current form depending on a result.Code Snippets
include Wicked::Wizard
steps <list_of_your_steps>
def new
session[:order_id] ||= Order.create.id
end
def show
@order = Order.find(session[:order_id])
end
def update
@order = Order.find(session[:order_id])
@order.assign_attributes(params[:order_params])
@order.current_step = step
render_wizard @order
enddef update
@order = Order.find(session[:order_id])
@order.assign_attributes(params[:order_params])
@order.current_step = step
@order.do_sth if step == :my_step
render_wizard @order
endContext
StackExchange Code Review Q#39470, answer score: 5
Revisions (0)
No revisions yet.