RoR and Relational databases: handling Model default values in database - ruby-on-rails

I'm working on a RoR project for work, and I'm having trouble deciding about the design of my relational database tables.
Consider the following:
I've got a model Product, each product has a unique name.
I've also got a model called Shop, each shop has many products.
Finally, I have an Order model, Order is obviously connected to the shop which the order has been made from, and to the list of products which were ordered.
I would like to keep default values (e.g. default price) for each product, and I'd like each Shop to be able to overwrite those default values if needed, but can't really decide on the strategy of doing so.
What I have in mind is as follows:
Create a Product table, which will include the product name, and also, columns to keep the product's default values (e.g. price)
Create a Shop table, which will include everything which has to do with the shop.
Create a Product_To_Shop table, which will hold the product quantity for that exact shop, and will hold additional columns, which match the Product default values columns which will let the shop overwrite the default product related values.
Now when I'd like to get the price for a specific order, i'll first check out the Product_To_Shop table, for the related Product and Shop, and check the Price field for the matching row, and in case it's not set to a value (nil), head to the Product table and fetch the default price value for the relevant product.
The whole thing looks a bit complex for a task which seems a bit more trivial.
I was wondering if anyone ever had to deal with keeping default values in the database like that and has a more elegant solution, since this one seems like an overkill...

you can do the following
Create a Products table, which will include the products data ( but no prices).
Create a Shops table, which will include the shops data.
Create a Prices table, which will include Product_id, Shop_id, Price.
Shop_id defaulted to null which will indicate your default price
When you need the price get the one matching shop_id or isnull

Related

Should I use a model archive in rails

I have a model product with a has_many relation prices. The prices table is growing rapidly, only few current prices are normally needed, but I want to keep all as a history.
So I am thinking to "archive" all old prices. How do I do that best?
Before I had a column old and was filtering them out when ever I only wanted the current prices. But now the prices table has 2.5 million rows and only 200k are needed in most situations. That's why I thought I would just create a new model price_archive. Copy all "old" prices to price_archive and delete it from prices. And all logic will be moved to a module, used by both models, so I can use price and price_archive in the same way.
Pros for the archive approach:
~ most of the queries are done on the smaller data set (200k, not much growing)
Cons:
displaying both ordered by time needs to be sorted on some kind of joined data set, because times overlap. So it looks like (part.prices.to_a + part.prices_archive.to_a).sort(&:time). Not a big problem, because this will be used very soldomly. But:
I have other models (i.e. order) that use prices in a belongs_to relation, so those need price_id and price_archive_id (with one id always being nil), so that they still reference a price.
Most queries are: show all prices for product (in a select box) and mark the price that is connected to this order (or add it to the select box, when it is archived)
So the code would be something like:
Order.where(*where*).includes(:part => :prices, :price, :price_archive)
The db will query: prices WHERE part_id = ? [on 200k] + prices WHERE id = ? [on 200k] + price_archives WHERE id = ? [on 2300k, but with primary_key]
instead of prices WHERE part_id = ? [on 2500k, with normal index]
Is there a better way or should I stay with the old column?

How to define a relationship in a rails model where the model has foreign keys that reference static values in another table

I have user objects that need to reference static values on foreign tables. The users have a fashion choice and a food choice. The fashion choice and food choice tables are simply a list of strings matched with an id. Storing the values in a separate file (CSV, JSON) isn't appropriate for my business case.
I defined a custom method:
def fashion_choice
FashionChoice.find_by(id: self.fashion_choice_id)
end
Which works fine, but gives me an N+1 problem because I can't use includes in my ActiveRecord queries, due to the association being defined in a custom method.
I am aware that I can use something like belongs_to in the user model to tell rails that the key lies in the Users table, but that feels strange to say that a User belongs to a fashion choice. Is there a better way to do this, or do I just have to do it the idiomatic Rails way?
User table:
id name fashion_choice_id food_choice_id
FashionChoice table:
id name
1 Halloween
2 Holiday
3 Beach Santa
FoodChoice table is similar.

Pseudo Table entries

I'm a learning developer building a Product & Inventory tracking platform for the company I work at and my Rails application has a Products table. Within the Products table are a bunch of basic entries, such as SKU, Description, UPC, Manufacturer, etc.
What I want to do is have an option within the Create page to insert custom parameters into something like a text_area to create Product specific entries, for example if I have only a small set of products that would benefit from a Voltage column and don't want to flood my migration with a bunch of lesser used options. What I'm picturing:
'Voltage|120 Volts'
'Housing Material|Steel'
'Duct Size|4"'
and then these could be their own rows in the Product's Show page.
Is anybody aware of a Gem or template that already accomplishes this, or would I need to dive in the deep end myself? I fear something like this is out of my skillset currently.
You can have one hstore column in the migration which will allow you to store multiple dynamic values in the single column as a hash.
You can read more about hstore from here.
I used hstore to store dynamic variants of product in the table.

ER Model representing entities not stored in DB and user choice

I'm trying to create a ER diagram of a simple retail chain type database model. You have your customer, the various stores, inventory etc.
My first question is, how to represent a customer placing an order in a store. If the customer is a discount card holder, the company has their name, address etc, so I can have a cardHolder entity connect to item and store with an order relationship. But how do I represent an order being placed by a customer who is not really an entity in the database?
Secondly, how are conditional... stuff represented in ER diagrams, e.g. in a car dealership, a customer may choose one or more optional extra when buying a car. I would think that there is a Car entity with the relevant attributes and the options as a multi-valued attribute, but how do you represent a user picking those options (I.e. order table shows the car ordered, extras chosen and the added cost of extras) in the order relationship?
First, do you really need to model customers as distinct entities, or do you just need order, payment and delivery details? Many retail systems don't track individual customers. If you need to, you can have a customer table with a surrogate key and unique constraints on identifying attributes like SSN or discount card number (even if those attributes are optional). It's generally hard to prevent duplication in customer tables since there's no ideal natural key for people, so consider whether this is really required.
How to model optional extras depends on what they depends on. Some extras might be make or model-specific, e.g. the choice of certain colors or manual/automatic transmission. Extended warranties might be available across the board.
Here's an example of car-specific optional extras:
car (car_id PK, make, model, color, vin, price, ...)
car_extras (extra_id PK, car_id FK, option_name, price)
order (order_id PK, date_time, car_id FK, customer_id FK, payment_id FK, discount)
order_extras (order_id PK/FK, car_id FK, extra_id PK/FK)
I excluded price totals since those can be calculated via aggregate queries.
In my example, order_extras.car_id is redundant, but supports better integrity via the use of composite FK constraints (i.e. (order_id, car_id) references the corresponding columns in order, and (car_id, extra_id) references the corresponding columns in car_optional_extras to prevent invalid extras from being linked to an order).
Here's an ER diagram for the tables above:
First, as per your thought you can definitely have two kinds of customers. Discount card holders whose details are present with the company and new customers whose details aren't available with the company.
There are three possible ways to achieve what you are trying,
1) Have two different order table in the system(which I personally wouldn't suggest)
2) Have a single Order table in the system and getting the details of those who are a discount card holder.
3) Insert a row in the discount card holder table for new/unregistered customers having only one order table in the system.
Having a single order table would make the system standardized and would be more convenient while performing many other operations.
Secondly, to solve your concern, you need to follow normalization. It will reduce the current problem faced and will also make the system redundant free and will make the entities light weighted which will directly impact on the performance when you grow large.
The extra chosen items can be listed in the order against the customer by adding it at the time of generating a bill using foreign key. Dealing with keys will result in fast and robust results instead of storing redundant/repeating details at various places.
By following normalization, the problem can be handled by applying foreign keys wherever you want to refer data to avoid problems or errors.
Preferably NF 4 would be better. Have a look at the following link for getting started with normalization.
http://www.w3schools.in/dbms/database-normalization/

Constructing a 1-many relationship with custom string foreign keys in PGSQL ActiveRecord

I have the following tables (Showing only the relevant fields):
lots
history_id
histories
initial_date
updated_date
r_doc_date
l_doc_date
datasheet_finalized_date
users
username
So I am rebuilding an exisiting application that dealt with a rather large amount of bureaucracy, and needs to keep track of five separate dates (as shown in the histories table). The problem that I am having is that I don't know how best to model this in ActiveRecord, historically it's been done by having the histories tables represented as so:
histories
initial_date
updated_date
r_doc_date
l_doc_date
datasheet_finalized_date
username
Where only one of the five date fields could ever be filled at one time...which in my opinion is a terrible way to go about modeling this...
So basically I want to build a unique queryable connection between every date in the histories table and its specific relevant user. Is it possible to use every timestamp in the histories table as a foreign key to query the specific user?
I think that there's a simpler approach to what you're trying to accomplish. It sounds like you want to be able to query each lot and find the 'relevant user' (I am guessing that this refers to the user who did whatever action is necessary to update the specific column on the histories table). To do this I would first create a join table between users and histories, called user_histories:
user_histories
user_id
history_id
I would create a row on this table any time a lot's history is updated and one of the relevant dates changes. But that now brings up the issue of being able to differentiate which specific date-type the user actually changed (since there are five). Instead of using each one as a foreign key (since they wouldn't necessarily be unique) I would recommend creating a 'history_code' on the user_histories table to represent each one of the history date-types (much like how a polymorphic_type is used). Resulting in the user_histories table looking like this:
user_histories
user_id
history_id
history_code
And an example record looking like this:
UserHistory.sample = {
user_id: 1,
history_id: 1,
history_code: "Initial"
}
Allowing you to query the specific user who changed a record in the histories table with the following:
history.user_histories.select { |uhist| hist.history_code == "Initial" }
I would recommend building these longer queries out into model methods, allowing for a faster, cleaner query down the line, for example:
#app/models/history.rb
def initial_user
self.user_histories.select { |uhist| hist.history_code == "Initial" }
end
This should give you the results you want, but should get around the whole issue of the dates not being suitable for foreign keys, since you can't guarantee their uniqueness.

Resources