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 :
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
end
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 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
end
-
\$\begingroup\$ If you found @BroiSatse's answer helpful, please checkmark it. \$\endgroup\$Cary Swoveland– Cary Swoveland2014年02月27日 20:40:30 +00:00Commented Feb 27, 2014 at 20:40
1 Answer 1
I would advise you to look at wicked gem: https://github.com/schneems/wicked.
Using this gem you could write:
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
end
It 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
end
render_wizard
automatically tries to save an object and redirects you to the next step or renders current form depending on a result.