Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
  end
like image 768
Brandon Hansen Avatar asked Oct 15 '25 10:10

Brandon Hansen


1 Answers

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
like image 124
Chris Heald Avatar answered Oct 17 '25 02:10

Chris Heald



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!