Ruby on Rails 3 - Modeling Products with Many Categories / Attributes - ruby-on-rails-3

I am working on my first Rails website, a sort of shopping website: there are products sold through the website, each with multiple unique attributes.
The use case I am imagining is: a user visits the site looking to buy a used bed, they click through several higher categories until they find a bed of the correct size, something like this:
Furniture
---> Couch
---> Dresser
---> Bed
-------> Size
----------> King
----------> Queen
...
At each time the user clicks a more narrow category, they are supplied a menu with the next level of detail (a la NewEgg). When "Furniture" is clicked, all furniture is displayed, and a menu with the types of furniture appears. When "Bed" is clicked, all beds are displayed, and a menu showing the various attributes of a bed appears, etc.
So far, I have an "Item" parent class which contains all the attributes of every item sold through the website (price, description, etc...). I am stuck with what to do next.
My first instinct is to have subclasses, but they don't seem to be that useful. There is nothing about the "Furniture" subclass that would have anything new in it, other than definiting it to be furniture. Also, each parent class needs to know about its subclasses.
What sort of design pattern should I pursue to cleanly implement this model? I've been looking into nested sets, but I am not completely sure that's the way to go. Any guidance is appreciated.
Thanks!

Your categories clearly form a tree, which is probably why you're thinking about a class inheritance tree. However, you are correct that this isn't the right model, since subclasses do not add any functionality over their parents.
You should have a single "Item" class, which is a node in the category tree - with references to its parent category (another "Item", or null for the root) and its array of children (all "Item"s).
The correct place to store the information about the tree structure is the database. In your items table, add a "parent_id" column as a foreign key - to the items table.
As the user navigates down in the tree you show the subcategories by querying for the items whose parent_id equals the current item id.

Related

Database design for a product-configurator

I have been asked by a customer to develop a "product configurator", and i need some inputs on how to handle the DB part of the project.
Each product can have a subset of different precreated attributes.
The minimum is 1 attribute, but there is no maximum.
Some attributes have dependencies/relationships with other attributes.
Eg. If the product is a chair, you need to choose the material (wood, plastic, metal), and you need to choose which type of legs the chair shoud have.
If the Product is a cabinet, you still need to choose a material, but instead of legs there will be different doors to choose from etc.
Each of these attributes might have subattributes. Eg. the door has a color, a size and a doorhandle.
Then the door handle has a material, a type and so on.
This ultimatly ends up in a multi-layered attribute-tree.
By itself this isnt too complicated to code, however the customer wants to be able to manage (Create, update and delete) all products, attributes and relationships between attributes, within the webapp.
So coding the relationship-part isn't a viable solution.
I have gone with a EAV model to facilitate the "potential unlimited" amount of attributes each product can have.
But i am struggling to figure out how to go about the "attribute relationships".
A simplified version of my DB design looks like this:
If each product could subscribe to groups of attributes that is legal. Then each attribute belongs to a group like "wood group".
Then the user could set the groups of attributes against a product that should need to be answered to configure a product.
With regards managing a tree, you could use a column type of hierarchyid . Or construct an outline string as key field.
An outline for example
1.
1.1.
1.1.1.
1.2.
2.
2.1.

How do i continue this database? (linking characteristics with predefined values to categories)

I'm struggling to understand how i need to do this. So my problem: I'm supposed to allow someone to sell a product on a website. Before selling, he has to chose a certain category. Each category has different characteristics that could be marked, and those characteristics are entirely dependent on the chosen category. The values of those characteristics are predefined, and are already put in the database.
My question now is how do i go on about this? How do i link those characteristics to the chosen category, and how do i link the different amounts of predefined values to those specific characteristics?
example:
category: keyboard
characteristics: condition (dropdown), keyboard layout(dropdown), extra options(multiple choice)
condition has 3 options: new, as good as new, used
keyboard layout has 2 options: qwerty, azerty
extra options is multiple choice, has 3 options: gaming keyboard, wireless, 60%
second example:
category: laptop
characteristics: condition (dropdown), refresh rate(dropdown)
condition has 3 options: new, as good as new, used
refresh rate has 5 options: 50hz, 60hz, 120hz, 144hz, 240hz
Now i would have to make this work in my database, but i can't even figure it out on a relational database diagram.
Any form of help would certainly be appreciated!
I would distribute fields like this:
CATEGORIES (keyboard, laptop)
id
name
ATTRIBUTES (refresh_rate, layout)
id
name
FEATURES (50hz, 60hz, qwerty, etc)
id
attribute_id
name
CATEGORIES_ATTRIBUTES
id
category_id
attribute_id
PRODUCTS
id
name
category_id
condition (could be an enum, I put it here as every product has a condition)
PRODUCT_FEATURES
product_id
attribute_id (redundant but it can save you a join when making queries)
feature_id
Cheers!

Most appropriate way to store/retrieve User Input in a eCommerce iOS application?

I'm a bit confused with Sqlite, Core Data, NSUserDefaultsand PropertyList. I know what is what, but not a very clear idea of about where to appropriately use them.
I know that there are lots of tutorials, but I'm good at learning through situation based understanding. So kindly do help me to understand this in the situation that I'm facing right now and to make use of the available options wisely.
I'm working on an ECommerce iOS (native) application, where I'm highly dependent on API's for data display. Now I'm in need of recording user's review for a product and send it over through an API.
ie. I have three components, rating title, rating value(for that title) and another rating title ID. I'm defining with an example, I need to store multiple rows with details,
Components Data to be stored
**Title** - Quality | Value | Price
| |
**Rating** - 2 | 3 | 1
| |
**TitleID** - 10 | 11 | 12
Like this, there will be so many entries, i.e, the number of components differs for various users, for some users, there might be more than three components, which must be saved & send through an API. So how should I save these data? which is the RIGHT way to save these data temporarily?
If I understand you correctly, as vaibhav implied your question seems pretty general and probably relates more to structuring your data to fit your requirements than to technical aspects of the iOS / CoreData environment. In that vein, I’ll offer a few thoughts I’d have in structuring a data structure for quality ratings per your description.
If your ratings will always be for the three categories you show, i.e. Quality, Value and Price, I wouldn’t over-complicate things; I’d just use three properties in a rating record to hold the values that a user assigns in his/her rating of a product (just showing selected attributes and relationships in all following lists):
Product
name
Rating
ratedProduct (many to one)
qualityRating Int
valueRating Int
priceRating Int
Done this way you’d need to associate the values with their types in code for the APIs, such as (where item is a retrieved rating record):
display(product: item.ratedProduct.name, quality: item.qualityRating, value: item.valueRating, price: item.priceRating).
On the other hand, you may be describing a more generic approach that would allow for ratings categories that vary more frequently, or perhaps vary among products. This could apply where, for example, ratings include how well things fit for clothing but not for other products like books. In that case, you’d need a more complicated structure where a product could have a variable number of ratings of different types, so you’d need another layer of entities that let you create an arbitrary number of rating records that applied to a product.
Here you'd create a separate rating record for each rating that a user assigned to a product.
The simplest form of that structure would be like the following:
Product
name String
UserEvaluation
ratedProduct (many to one)
productRating (one to many)
ProductRating
ratingType (many to one)
value Int
RatingType
ratingTitle String
ratingID String or Int
Then you’d have to have a bit more structure where you'd list the product and then access the ratings with a loop that cycled through the set of all of the ratings linked to the product record somewhat like this (where item is a retrieved UserEvaluation):
displayTitle(product: item.ratedProduct.name)
for rating in item.productRating {
displayRating(ratingTitle: item.productRating.ratingType.title, ratingValue: item.productRating.value)
}
You'd probably want to combine these into a method that takes the name and an array of ratings.
To keep track of things, you’d also probably want to create another entity that defined product classes and specified what specialized ratings applied to each class (like fit for clothing and mileage for cars). By default, you also may want to allow for a few generic rating types that apply to all products (like the quality and price ratings you show). For this approach, the full structure would look like this:
Product Category
title
ratingType (many to many)
Product
productType (many to one)
UserEvaluation
ratedProduct (many to one)
productRating (one to many)
ProductRating
ratingType (many to one)
value Int
RatingType
ratingTitle String
ratingID String or Int
With this structure, once a product is assigned a productType, the application would know what ratings to ask for in the UI.
You could try building more complicated rating records with all of the types that apply to a product category, but that would get very messy if the applicable categories vary over time. You could also create a "custom" rating type that let a user specify a title and input a rating, in which case you'd need a text field in the rating record that only applies if the ratingType is "custom".
I hope this helps…

Which is the best design for categorizing items?

I have four levels for categorizing items according to their attributes. Some items may not require all subcategory levels and some items may share the same subcategory values.
Examples:
Category1 Category2 Category3 Category4
--------- --------- --------- ---------
Jewelry Ring Wedding
Jewelry Bracelet Serpentine
Jewelry Necklace Serpentine
Equipment Tool Power Drill
Equipment Tool Hand Jigsaw
Accessory Battery AA
Accessory Movie DVD Action
Accessory Game PS3 Combat
I want the lookup tables to contain values which are related to each item so that when users select a value from the dropdown list in the first category, the corresponding values in the next subcategory will automatically drop down (cascade), and so on.
I will predefine non-deletable, non-updatable values for most common items, however I cannot provide all possible items, for which I want to allow users to add values from the second level on down.
The objective for classifying each item is to provide a uniform method for describing items and for queries to effectively return all desired items.
Questions:
How can I make sure that new values which are added by users will link properly to parent or child values?
Should I allow users to add new categories and subcategories or should I force them to only select from pre-defined values, chose 'Other' value if their item does not fit into one of the pre-defined and enter a free-form comment?
Is the current method I have defined the best way or do you have a better suggestion?
Below are the current tables and relationships I have defined:
Columns MS-Access Informix Comments
-------------- ------------ -------- ----------------------------------------
Primary keys Autonumber SERIAL
Foreign keys Long Integer INTEGER
English Text VARCHAR Description in English language.
Spanish Text VARCHAR Description in Spanish language.
NonDelete Yes/No CHAR(1) Cant delete predefined value if TRUE.
NonUpdate Yes/No CHAR(1) Cant update predefined value if TRUE.
Deleted Yes/No CHAR(1) User-defined value cant be used anymore.
StockKeptUnit Yes/No CHAR(1) Non-serialized inventory item if TRUE.
Don't they properly link by definition? That is sort of the point of the PK/FK relationship, after all.
Presumably creation of a new tlkpItemCat2 involves selecting a valid parent tlkpItemCat1, or the INSERT would fail. As long as tlkpItemCat2.ItemCat1_SIID is defined as NOT NULL, you're pretty much assured of a valid relationship.
That doesn't guarantee that the end-user hasn't declared that a Necktie is a Power Tool, but that's a whole different problem.
Now, from experience with this exact issue (object categorisation), I can tell you that although this design looks quite elegant and useful, it is awful from a usability perspective. Your user has to know the hierarchy in advance to quickly locate the correct category for an item. And once end-users start adding levels to your hierarchy, it becomes a nightmare of back-and-forth, dead-end searches trying to locate the correct combination of Cat1/Cat2/Cat3 to apply - which leads to anything-will-do-just-to-get-past-this-screen categorisation.
A better approach is to allow the user to simply type in 'Jigsaw', and return a list along the lines:
Did you mean:
[] Equipment | Tool | Power | Jigsaw
[] Equipment | Tool | Hand | Jigsaw
[] Game | Childrens | Jigsaw
[] Accessory | DVD-Movie | Horror | Jigsaw
[] ... or [something else]?
Yes, it's more work, but from a UI and UX perspective, worthwhile.
This should allow for infinite categories. You'll need to enforce non-orphaning through your UI or OnChange events.
Then your table content would look like this:

Modeling related entities with SQL Server and entity framework

I've got a table in my database storing items:
Items
-------
ItemID
Name
...
Etc
and a separate table storing the PK of two different items from the first table. I want to be able to list the one item, and then any number of related items. I've tried searching for examples but haven't found much surprisingly...
RelatedItems
------------
ItemID
RelatedItemID
If I have four products, whose IDs are 1, 2, 3 and 4... and 1 is related to 2 and 3 I might have data that looks like this:
ItemID RelatedItemID
1 2
1 3
4 1
I am then modeling them in the Entity Framework Designer, and the designer automatically adds an association from the Items table to itself (many to many). The designer also adds two navigation properties, if I use the first property on Item #1 I get all items where Item #1 is in the first column, and if I use the second property I get all the items where Item #1 is in the second column.
I however just want to have one navigation property where I can say Items.RelatedItems and it returns all the items that the above two properties would when combined. I know I can join the two results after the fact but I can't help to think I'm doing something wrong and there is a better way.
Hopefully this is all clear enough.
It sounds like SQL schemas just aren't very good at modeling the concept you're looking for. The schema you've chosen would work well if you want to establish a directional relationship (item A is related to item B, but item B may or may not be related to item A). If you were looking for a grouping-style relationship (Items A and B are in the same group), I can think of a different approach you'd use. But I can't think of a good way to model an inherently bi-directional relationship using a traditional relational database.
Some workarounds might be to use a View that joins the two results, or to use triggers to make sure that every mapping from A to B has a corresponding mapping from B to A, so that both of the properties always return the same objects.
If you have an instance of an Item, call it item, then the following will give you the related items...
item.RelatedItems.Select(ri => ri.Item);
Your RelatedItems property on item (ie the first navigation property you mentioned) will be a collection of RelatedItem objects, each of which has two navigation properties of its own, one of which will be named Item and will be a link to the related item.
Note that this is air code, as I'm not in front of anything I can test this on right now, but I think this will do what you want.
If you want to make it simpler, you can write an extension method to wrap up the Select(), something like this...
public static IEnumerable<Item> RelItems(this Item item) {
return item.RelatedItems.Select(ri => ri.Item);
}
Then you could just do...
item.RelItems();
Note that I couldn't name the extension method RelatedItems, as that would clash with the navigation property that EF would have created for the second table. That's perhaps not a good name for that tables, as it's not the actual items, rather the IDs of the items. Either way, the above code should work.