Design Question

I’m having some trouble figuring out how to break a project into various
controllers. Here’s my situation. Say I’m building a small web store
that sells software. Each piece of software will belong to a given

Ok, so there are my two models ‘Software’ and ‘Vendor’. I’d like to be
able to do basic CRUD on both a Vendor and and or a Product. However, I
want the Vendor to be a sort of Gateway to the Product. So let’s say I
create the basic CRUD actions for the Vendor. If I’m viewing a Vendor’s
info–name, address, url, etc-- that’s where I would also see options
like: ‘List Products’, ‘Create Product’.

So the real question is should I use one controller or two controllers?

If I used one controller I would have actions like:

If I used two controllers:


@Chris…or anyone else who has an opinion

Thanks again for you detailed example. Just getting around to figuring
out how the whole Map.connect thing works and I’m a bit blown away at
it’s power.
The more I use rails the more I like it :slight_smile:

Anyway, in your previous post you mentioned how one option is to pass
the id of the vendor into the product controller. Then you could do
product actions specific to the vendor with a url like:


ok so my questions is about passing the vendor id around. I guess I’m
just lazy and wondering why not just set a session parameter and the
forget about passing the vendor id around while in the product
controller. What if in product/list I did something like:

def list
if params[:criteria] == ‘vendor’ && !params[:vendor_id].nil?
session[:vendor] ||= Vendor.find(params[:vendor_id]
# get list of products for this vendor
# get list of all products

Then in the rest of my product controller’s actions I could just check
to see if session[:vendor] is set, and act accordingly. In vendor/list
I could just blow the session var away ‘session[:vendor] = nil’

Anyway, I’ve done this type of thing in the past with php and it’s
worked fairly well. Just wondering if perhaps doing this may come back
to bite me and or if it violates any rails best practices.


Mike, Chris

Thanks for the feedback. I think I may go with the two controller
method since this is how I’ve done things in the past with the PHP
framework I was using.


if you notice, the only time the vendor info is getting passed via the
is when I am requesting information.

so for list and new actions, i would use:

/product/list/vendor/X # list products for vendor X
/product/new/vendor/X # show new product for and pre-select vendor X
the ‘new’ form

where X is the vendor id

i wouldn’t use it for the edit action, since the vendor would already
for that product, so a simple /product/edit/X (where X is the product
would suffice.

for create and update actions, the vendor ID would be submitted in the

so you really aren’t passing around the vendor ID except for those 2

it’s just my way of doing it. i’m sure there are just as many other
ways to accomplish the same thing. to me, it’s intiuitive and easy to


i do something like this, using the 2 controller method, within
/vendor/view, do:

link_to “view products for this vendor”, :controller => “product”,
=> :list, :criteria => “vendor”, :id =>
link_to “add new products for this vendor”, :controller => “product”,
:action => :new, :criteria => “vendor”, :id =>

in routes.rb, add (above the default route):

map.connect “/product/list/:criteria/:id”, :controller => “product”,
=> “list”, :criteria => nil, :id => nil, :requirements => { :id => /\d+/
map.connect “/product/list/:criteria/:id”, :controller => “product”,
=> “add”, :criteria => nil, :id => nil, :requirements => { :id => /\d+/

then in product controller:

class ProductController < ApplicationController
def list
case @params[:criteria]
when “vendor”

list products for a specific vendor

@products = Product.find_by_vendor_id(@params[:id])

otherwise just list all products

@products = Product.find_all

def new
case @params[:criteria]
when “vendor”

new product for a specific vendor (preset the vendor id so it is

in the view form)
@product = => @params[:id])
@product =

in the new.rhtml view, do:

<%= start_form_tag :action => :create %>
.<%= text_field(“product”, “name”) %>
<%= select(“product”, “vendor_id”, Vendor.find(:all).collect { |v|
[v.name,] }, { :include_blank => true }) %>
<%= submit_tag “save product” %>
<% end_form_tag %>

this should automatically select the vendor in the select options

hope this helps


On 11/21/05, Steven [email protected] [email protected] <

This is probably very subjective, but I build a controller for each
‘gateway’ as you put it.

For example, I would build a vendor controller that allowed the vendor
to do everything that was needed for its interface. I usually name my
actions things like “vendor_add”, “vendor_edit”, “product_add”,
“product_destroy”, etc just to make it more clear when reviewing

I suppose the next step would be an interface for customers, which you
might just call ‘store’ or something like that.

Hope this makes sense,


On 11/21/05, Steven [email protected] [email protected]