RESTful design/url question

New to rails and restful design, forgive me if this has been asked...

Lets say you have customers and orders models. orders belongs_to customers.

When viewing a customer, (/customers/1/) I want to present the option to view the customers orders (and eventually invoices, POs, etc). What route would be within restful guidelines?

/customers/1:orders /customers/1?view=orders /customers/1/orders/ /orders:filter?customer=1

I think I would prefer each "page" of a customer detail have it's own controller method -- this will allow me to keep the security decisions completely within the controller easily.

Thanks

New to rails and restful design, forgive me if this has been asked...

Not at all.

Lets say you have customers and orders models. orders belongs_to customers.

When viewing a customer, (/customers/1/) I want to present the option to view the customers orders (and eventually invoices, POs, etc). What route would be within restful guidelines?

/customers/1:orders /customers/1?view=orders /customers/1/orders/ /orders:filter?customer=1

I believe it would be /customers/1/orders/ . You achieve this by specifying that orders are nested within customers in your routes.rb:

map. resources :customers do |customer|   customer.resources :orders end

and then, in your OrdersController class, use a before_filter to identify the customer, something like:

before_filter :get_customer

def get_customer   @customer = Customer.find(params[:customer_id]) end

The customer_id key is automatically created for you when you nest the routes.

I think I would prefer each "page" of a customer detail have it's own controller method -- this will allow me to keep the security decisions completely within the controller easily.

That's how Rails works anyway - each "page" is an "action". An action is a coupling of a controller method and a template (.rhtml page). So you're on the right track.

Hope this helps Jeff softiesonrails.com

Thanks a bunch.

Follow-up question if you don't mind...

You are on the page to view a customers orders: /customers/1/orders/

User clicks edit, Would you replicate the edit, ala:

/customers/1/orders/1;edit

Or kick 'em to the orders resource?

/orders/1;edit

I'd like to be able to click "New Order" from within the customer view, something like

/customers/1/orders/new

But the replication doesn't feel very DRY.

you can use the builtin helper:

edit_order_path(@customer,@order)

that will create a link like “/customers/1/order/1;edit”

new_order_path(@customer) will create a link to “/customer/1/order/new”

ed

I understand that,

But in my instance orders is not only a child of customers, it's a bonafide resource of it's own, accessible via:

/orders/ /orders/1/ /orders/1;edit

So, if we are viewing a customer/orders page, /customers/1/orders/ and they click on "Edit Order". Do we goto:

/customers/1/orders/1;edit #edit order #1 Or /orders/1;edit #edit order #1

Do we implement both methods for the same function?

Syntactically, I think I like the both approach. If a user clicks on "Edit Order" from within a customer orders details view, its pretty apparent where they should return after completing the edit.

Meech,

Why do you want to expose orders as a first level resource (/orders/1)? If an order is always associated with a customer then the nested way (/customers/1/orders/1) makes more sense.

What is it you're trying to accomplish by exposing orders via two resource paths?

It depends on your model associations. If Order belongs_to Customer, then I would go the “/customers/1/orders/new” because you’ll need to reference to the Customer to create the Order. You can use nested routes to acheive this. Jamis Buck recently posted about something related to your question: http://weblog.jamisbuck.org/2007/2/5/nesting-resources

ed

It just seems nicer to be able to view open/active orders across customers to perform order-related functions. The user could goto:

/orders/?q=active

Click on the order and manipulate it, instead of remembering the customer, clicking on the orders tab, then clicking on the order.

But lets take this another level deep. Orders have invoices, invoices has payments.

customer --order ----invoice ------payment

A person in accounts receivable would like to see unpaid invoices (as a whole, not specific to a customer) in order to perform collection activities. Or be able to see payments within a deposit instead of by customer/invoice, etc, etc...

While somebody can view invoices via /customer/1/invoice/1/ how would they see all open invoices for the company? via: /invoices/

This is why I posed the original question. Is it restfull to duplicate functions like this?

Is it? /customers/1/invoices /invoices/customers/1/ /invoices/?customer=1

I understand where you're coming from now. I think you could do this a few ways. One is to just expose the additional route in routes.rb

map. resources :customers do |customer|   customer.resources :orders end map.admin_orders '/orders', :controller => 'orders'

You can also make an admin controller for handling workflow types of things like order approval (in non-REST fashion). Or you can view status changing of orders (aka pending, verified, charged, shipped, etc) as an OrderStatus resource and expose this via a REST controller.

Good luck.