Rails Routing Variables
Orders can have many states. I would like to create named routes for those. I need the state to be passed in to the controller as a param. Here is what I was thinking, but it obviously does not work.
match "order/:state/:id" => "orders#%{state}", as: "%{state}"
So I would like order/address/17 to route to orders#address, with :state and :id being passed in as params. Likewise, order/shipping/17 would route to orders#shipping, again :state and :id would be passed in.
Here is the controller.
class OrdersController < ApplicationController
before_filter :load_order, only: [:address, :shipping, :confirmation, :receipt]
before_filter :validate_state, only: [:address, :shipping, :confirmation, :receipt]
def address
@order.build_billing_address unless @order.billing_address
@order.build_shipping_address unless @order.shipping_address
end
def shipping
@shipping_rates = @order.calculate_shipping_rates
end
def confirmation
end
def receipt
end
private
def load_order
@order = Order.find(params[:id])
end
# Check to see if the user is on the correct action
def validate_state
if params[:state]
unless params[:state] == @order.state
redirect_to eval("#{@order.state}_path(:#{@order.state},#{@order.id})")
return
end
end
end
end
Here is what we ended up going with:
routes.rb
%w(address shipping confirmation receipt).each do |state|
match "order/#{state}/:id", :to => "orders##{state}", :as => state, :state => state
end
orders_controller.rb
def validate_state
if params[:state]
unless params[:state] == @order.state
redirect_to(eval("#{@order.state}_path(@order)"))
return
end
end
开发者_JS百科 end
You aren't going to be able to create dynamic named routes with that sort of syntax, but you're basically just using :state
as the :action
. If you replace :state
with :action
and specify the controller manually, it'll work. Obviously, you will have to change your code to look at params[:action]
rather than params[:state]
(or map that variable in a before_filter), but beyond that it should work fine.
match "order/:action/:id", :controller => "orders"
Be aware that if orders has RESTful resource mappings like create
or delete
, this route would allow GET requests to them, which would be bad; you may just want to add explicit routes for each action you want to complete. This will let you get params[:state]
, as well:
%w(address shipping).each do |state|
match "order/#{state}/:id", :to => "orders##{state}", :as => state, :state => state
end
精彩评论