Topic: Catalog design

I've got a catalog with multiple levels of categorizing parts and I'm having trouble getting my brain around it.

16 categories
32 subcategories
82 groups
800 products

Basically, users will click on one of the top-level categories and be given a gallery of the subcategories. Clicking a subcategory will return a gallery of the groups in that category. Clicking a group will switch to a detail view with detailed part specs for the parts in that group.
I've created a controller for each, but now I'm thinking should I just have a catalog controller with a different view for each.

Re: Catalog design

You will want to use nested relationships to go about this in your models.

So something like:

Product model

belongs_to :group # group_id must exist in the products table

Group Model

belongs_to :subcategory
has_many :products, :dependent => :destroy
accepts_nested_attributes_for :products, :allow_destroy => true

Subcategory Model

belongs_to :category
has_many :groups, :dependent => :destroy
accepts_nested_attributes_for :groups, :allow_destroy => true

Category Model

has_many :subcategories, :dependent => :destroy
accepts_nested_attributes_for :subcategories, :allow_destroy => true

Then you need to change your routes in config/routes.rb.

map.resources :categories, :has_many => [:subcategories]
map.resources :subcategories, :has_many => [:groups]
map.resources :groups, :has_many => [:products]

In doing so, URL's are nested, and so you'd have a url say "http://FQDN/categories/1/subcategories/1/groups/1/products/1"

Does that make sense?

Re: Catalog design

It makes some sense.  I get the nested part, although I'm not sure about the :dependent => :destroy and :allow_destroy bits.

I've set this up in my models and route.rb and entered some sample data.
/categores/1 #works
/categories/1/subcategories/1 #works
/categories/1/subcategories/1/groups #returns no route matches error
/categories/1/subcategories/1/groups/1 #returns no route matches error

Something seems amiss with groups. I've verified there are groups that have a matching subcategory and category, but I can't get them to display.

Added note:
Well I copied my rake routes output to see if I could make some sense of this and I think I see the problem - just not sure how to fix it.

I can do /categories/n/subcategories/n
and I can do /subcategories/n/groups/n
I just can't do categories/n/subcategories/n/groups/n

I'm thinking I need something like map.resources :categories, :has_many => [:subcategories, :groups], but I haven't figured out how to make it work.

Last edited by Kurtismonger (2010-02-01 21:00:23)

Re: Catalog design

Not sure if this is progress or not; and I'm not sure why it's different (yet)
So I did my routes like this:
  map.resources :categories do |categories|
    categories.resources :subcategories do |subcategories|
      subcategories.resources :groups do |groups|
        groups.resources :products

When I do it that way I get a nomethod error, which I think means that the routes are working?!Maybe?
I realize that what jmbrink26 gave me was the shorthand version of using a block, I just haven't figured out how it's different from the block I wrote?

Last edited by Kurtismonger (2010-02-03 15:44:16)

Re: Catalog design

So any help here?  This is the error I'm getting:
NoMethodError in Subcategories#show

Showing app/views/subcategories/show.html.erb where line #25 raised:

undefined method `edit_subcategory_path' for #<ActionView::Base:0x10335fe40>
Extracted source (around line #25):

25: <%= link_to 'Edit', edit_subcategory_path(@subcategory) %> |
26: <%= link_to 'Back', subcategories_path %>

Re: Catalog design

I'm wondering if nested is even the way to go. I'm not crazy about have a huge path displayed. Basically I'm just trying to classify parts by category, subcategory and group.

Re: Catalog design

Before I give an answer I am wondering...

A couple of questions:
Can products belong to more than one group?
Can groups belong to more than one subcategory?
Can subcategories belong to more than one category?

This is important because it will determine how you set up your models and routes.


Re: Catalog design

At this point, no to all your questions. I might want products to belong to more than one group down the road, but it's not necessary now if it makes it more complicated.

I revised my post above, using the singular of each. This gives me what looks like the right routes, although I'm still throwing a nomethod error:
   map.resources :categories do |category|
     category.resources :subcategories do |subcategory|
       subcategory.resources :groups do |group|
        group.resources :products

Re: Catalog design

I'm open to any and all suggestions here. I'm still not sure nested routes are the way to go the more I cipher on this. I don't want to have to refer to one of the nested resources only in the context of their parent.

The original structure, as described in my first post, is so users can quickly narrow their search down to the group level, starting at the top-level category of parts if they are not sure of the part number they want. Products within a group are basically just variants of that group. So if there is a group called Widget1, there may be 6 products which are just different lengths of Widget1(6" Widget1, 8" Widget1, etc). The group-level contains the product photos and generals specs and description that those products share. The product level provides that part's specific dimensions and other details unique to the part. Other users may know the exact part number and plug it into a search box.

Re: Catalog design

Oof - I feel stupid. Just reread the Rails Guide on Associations and see at least part of my problem. I think I messed up my foreign keys in each table. Jmbrink26 told me and I looked right past it. Instead of having group_id, subcategory_id, and category_id to reference the related table I used groupindex, etc. I take it Rails needs it to be called whatzit_id for the magic to happen. Not sure if that is the cure or not, but I'm going try it out.

Re: Catalog design

Yeah, I'm stuck. I fixed my foreign key fields so I can reference things by URL, but I can't figure out how to present it to the user. The homepage has 16 icons (displayed using CSS sprites) representing the categories that users can click on. I then want to show them the subcategories for that particular category, if any. From there they will click on a subcategory to show them the groups available. Clicking on a group will take them to a detail page that shows them the part details for those particular group of parts.
I asked this before, but didn't really get a straight answer. I have MVCs for each category, sub, group, product but in order to make the functionality I describe above do I need a separate catalog MVC?

Last edited by Kurtismonger (2010-02-09 13:57:44)

Re: Catalog design

Did you ever figure this out?  I may be able to help.  I have a site running that has 3 levels of the same org structure you are referring to.

Re: Catalog design

Thanks for the followup. I did not solve it and I had shelved that project. I just recently pulled it back out to see if Rails 3 would make it easier for me to get a handle on what I am trying to do. I can't say whether it does yet, as I'm still walking through the changes.

Re: Catalog design

I took some time off to study up on Rails (using 2.3.8), work through a bunch of tutorials, make some simpler apps and I've now picked this project back up. I have most of the job done as far as generating static pages and the CRUD for categories, subcategories, groups and products for admin purposes. However I'm still having trouble displaying subcategories, groups and products in the catalog gallery. I can display categories fine, since I will always want to show all categories. But I want to be able to show one or more subcategories based on the category the person clicks on. And then on down the line: They would then click on a subcategory to see one or more groups in that subcategory and finally click a group to be shown the part detail page which lists one or more parts in a particular group. Right now I'm just trying to display the appropriate subcategory as the rest that follow will be basically the same thing (groups, products)

Each level of the catalog has a foreign key to it's parent with the appropriate relationships in the models:
category      has_many  :subcategories
subcategory belongs_to :category          has_many :groups     FK = category_id
group          belongs_to :subcategory     has_many :products   FK = subcategory_id
product        belongs_to :group              FK = group_id

Here is my routes.rb

  map.root      :controller => 'pages'
  # I was experimenting with this and could get it to display the appropriate subcategories, but only if I hand coded the catalog_id in my show_subcategory action
  # map.connect   '/catalog/subcategory/:category_id', :controller => 'catalog', :action => 'show_subcategory'
  map.show_subcategory  'catalog/:category_id', :controller => 'catalog', :action => 'show_subcategory'

  map.resources :categories
  map.resources :subcategories
  map.resources :groups
  map.resources :products
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'

Here is the catalog controller action:

  def show_subcategory
    @subcategory = Subcategory.find(params[:category_id])
    render( :partial => "show_subcategory", :collection => @subcategory )

Finally (whew!), this is the call from my navigation:

<li><%= link_to 'Cleats',  show_subcategory_path(:category_id => 1), :class => 'nav_cleat' %></li>

The above returns undefined method `map' for #<Subcategory:0x103324c28>

I've tried a bunch of different things, but can't quite seem to get there.

Last edited by Kurtismonger (2011-06-19 14:57:37)