# Design Question

**URL:** <https://www.ruby-forum.com/t/design-question/48557>\
**Category:** Rails\
**Created:** [November 22, 2005, 3:49am UTC](https://www.ruby-forum.com/t/design-question/48557 "2005-11-22T03:49:37Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Steven\_SS\_SS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7ba0ec/32.png) [@Steven\_SS\_SS](https://www.ruby-forum.com/u/Steven_SS_SS)\
**Post date:** [November 22, 2005, 3:49am UTC](https://www.ruby-forum.com/t/design-question/48557/1 "2005-11-22T03:49:37Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Steven\_SS\_SS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7ba0ec/32.png) [@Steven\_SS\_SS](https://www.ruby-forum.com/u/Steven_SS_SS)\
**Post date:** [November 28, 2005, 1:50am UTC](https://www.ruby-forum.com/t/design-question/48557/2 "2005-11-28T01:50:25Z")

</div>

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

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

---

<div class="post-metadata">

**Author:** ![Steven\_SS\_SS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7ba0ec/32.png) [@Steven\_SS\_SS](https://www.ruby-forum.com/u/Steven_SS_SS)\
**Post date:** [November 22, 2005, 3:48pm UTC](https://www.ruby-forum.com/t/design-question/48557/3 "2005-11-22T15:48:01Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Steven\_SS\_SS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7ba0ec/32.png) [@Steven\_SS\_SS](https://www.ruby-forum.com/u/Steven_SS_SS)\
**Post date:** [November 28, 2005, 2:48pm UTC](https://www.ruby-forum.com/t/design-question/48557/4 "2005-11-28T14:48:42Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Steven\_SS\_SS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7ba0ec/32.png) [@Steven\_SS\_SS](https://www.ruby-forum.com/u/Steven_SS_SS)\
**Post date:** [November 22, 2005, 1:24pm UTC](https://www.ruby-forum.com/t/design-question/48557/5 "2005-11-22T13:24:44Z")

</div>

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](http://vendor.id)  
link\_to “add new products for this vendor”, :controller =\> “product”,  
:action =\> :new, :criteria =\> “vendor”, :id =\> @vendor.id  
[http://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.name[http://v.name](http://v.name),  
v.id [http://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 [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) \<

---

<div class="post-metadata">

**Author:** ![Steven\_SS\_SS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/7ba0ec/32.png) [@Steven\_SS\_SS](https://www.ruby-forum.com/u/Steven_SS_SS)\
**Post date:** [November 22, 2005, 1:00pm UTC](https://www.ruby-forum.com/t/design-question/48557/6 "2005-11-22T13:00:35Z")

</div>

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 [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)
