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
Vendor.

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:
/admin/vendor/add
/admin/vendor/list
/admin/vendor/view
/admin/vendor/add_product
/admin/vendor/list_products
/admin/vendor/view_product

If I used two controllers:
/admin/vendor/add
/admin/vendor/list
/admin/vendor/view
/admin/product/add
/admin/product/list
/admin/product/view

Thanks,
Steven

@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:

product/list/vendor/5
product/new/vendor/5
product/edit/66/vendor/5

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
else
# get list of all products
end
end

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.

-Steven

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.

-Steven

if you notice, the only time the vendor info is getting passed via the
URL
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
in
the ‘new’ form

where X is the vendor id

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

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

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

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

Chris

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

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

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

map.connect “/product/list/:criteria/:id”, :controller => “product”,
:action
=> “list”, :criteria => nil, :id => nil, :requirements => { :id => /\d+/
}
map.connect “/product/list/:criteria/:id”, :controller => “product”,
:action
=> “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])
else

otherwise just list all products

@products = Product.find_all
end
end

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

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

selected
in the view form)
@product = Product.new(:vendor_id => @params[:id])
else
@product = Product.new
end
end
end

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.namehttp://v.name,
v.id http://v.id] }, { :include_blank => true }) %>
<%= submit_tag “save product” %>
<% end_form_tag %>

this should automatically select the vendor in the select options

hope this helps

Chris

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
later.

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,

Michael

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