Ruby on rail multiple product possibility on invoice table - sql

I have by the moment 4 tables on my web-market.
Table User: Username + password + email.
Table Serie: Serie name + price + description
Table Season: Season name + price + description + fk(Serie) //Each season belongs to a serie
Table Chapter: Chapter name + price + description + fk(Season) //Each chapter belongs to a season
The user would be able to buy either series seasons and chapters. The main idea is the following:
Table invoice: fk(user) //User have multiple invoices
Table invoice_line: fk(invoice), fk(serie|season|chapter) //Each invoice contains multiple products
How can I represent that serie|season|chapter relation easily?

You could use polymorphic association from Active Record.
It can be represented like this:
class InvoiceLine < ActiveRecord::Base
belongs_to :invoice
belongs_to :containable, polymorphic: true
end
With this definition you should have table like this:
create_table :invoice_lines do |t|
t.references :invoice,
t.references :containable, polymorphic: true
end
t.references :containable, polymorphic: true will create both integer containable_id and string containable_type columns.

Related

database design (joining 3 tables together)

My goal is to create a web app that show elections results from my country.
The data is the results for every candidates in every city for every election.
An election has many candidates and many cities.
A candidate has many elections and many cities.
A city has many elections and many candidates.
For the 2nd round of the last presidential election:
City
inscrits
votants
exprime
candidate1
score C1
candidate2
score C2
Dijon
129000
100000
80000
Macron
50000
Le Pen
30000
Lyon
1000000
900000
750000
Macron
450000
Le Pen
300000
How can I join those 3 tables together?
Is it possible to create a join table between the three, like this?
create_table "results", force: :cascade do |t|
t.integer "election_id", null: false
t.integer "candidate_id", null: false
t.integer "city_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["city_id"], name: "index_results_on_city_id"
t.index ["candidate_id"], name: "index_results_on_candidate_id"
t.index ["election_id"], name: "index_results_on_election_id"
end
But in this case, where can I add the city infos for election? (Column 2, 3, 4 of my data example, i.e: in this city, for this election XXX people voted, XXX didn't vote.)
I came with this database schema:
my database schema
This will not work because I will not be able to access the result of a candidate in a specific city for a specific election. It looks like there is no connection between cities and candidates.
To actually tie these models together and record the data required you need a series of tables that record the election results at each level your interested in:
# rails g model national_result candidate:belongs_to election:belongs_to votes:integer percentage:decimal
class NationalResult < ApplicationRecord
belongs_to :candidate
belongs_to :election
delegate :name, to: :candidate,
prefix: true
end
# rails g model city_result candidate:belongs_to election:belongs_to votes:integer percentage:decimal
class CityResult < ApplicationRecord
belongs_to :city
belongs_to :candidate
belongs_to :election
delegate :name, to: :candidate,
prefix: true
end
Instead of having C1 and C2 columns you should use one row per candidate instead to record their result. That will let you use the same table layout even if there are more then two candidates (like in a primary) and avoids the problem of figuring out which column a candidate is in. Use foreign keys and record the primary key instead of filling your table with duplicates of the names of the candidates which can easily become denormalized.
While you might naively think "But I don't need NationalResult, I can just sum up all the LocalResult's!" - that process would actually expose any problems in your data set and very likely be quite expensive. Get the data from a repubable source instead.
You can then create the has_many assocations on the other side:
class Canditate < ApplicationRecord
has_many :local_results
has_many :national_results
end
class Election < ApplicationRecord
has_many :local_results
has_many :national_results
end
class City < ApplicationRecord
has_many :local_results
end
Keeping track of the number of eligable voters per election/city will most likely require another table.

Rails how to create a different table for each user

I have two tables account and display_colors. The display_colors table has 10 default ids with color codes. If one user changes the color the colors for all user gets changed.
I'm trying to find out if there is a way to create a different table for each user or any other options I have without changing the actual logic of my frontend.
I tried using association belongs_to and has_many where display_colors have a column account_id but it is getting changed on each and every update.
display_color.rb
#TODO: Add for account level
belongs_to :account
def self.update_colors(colors)
import colors, on_duplicate_key_update: { conflict_target: [:id], columns: [:max_range, :color_code] }
end
def self.color_code(conf)
rounded = (conf * 100).round
where("min_range <= ? AND max_range >= ?", rounded, rounded).first.try(:color_code)
end
end
Account.rb
class Account < ApplicationRecord
has_many :display_colors
validates_uniqueness_of :name
def self.default
where(name: 'default').first
end
end
The screenshot shows the db table looks like. I have 10 columns in there those 10 must be unique to a user with default values for each account at the beginning.
https://i.stack.imgur.com/Z2GHh.png

Alternative to a union with ActiveRecord

I think I want to do a union in Rails, but according to this post rails union hack, how to pull two different queries together unions aren't natively supported in Rails. I'm wondering if there is a better way to approach this problem.
I have table of items, each item has many prices, but I only want to join one price to each item.
To determine the proper price for an item I have two additional foreign keys in the price model: category_id and discount_id. Each could independently declare a price for an item.
Ex.
Item + Category = Price1 and Item + Discount = Price 2
If discount_id matches a passed id I want to exclude the price results FOR THAT ITEM ONLY that match Item + Category. Also I'm trying not to loose lazy loading.
Hopefully the problem is clear! If not I'll try to clarify more, thanks in advance.
Your models would start off looking something like this:
class Price < ActiveRecord::Base
belongs_to :item
belongs_to :category
belongs_to :discount
scope :category, where("prices.category_id IS NOT NULL")
scope :discount, where("prices.discount_id IS NOT NULL")
end
class Item < ActiveRecord::Base
has_many :prices
end
class Category < ActiveRecord::Base
has_many :prices
end
class Discount < ActiveRecord::Base
has_many :prices
end
One way of doing this is to add a class method to Price that encapsulates this logic:
class Price < ActiveRecord::Base
def self.used
discount_items_sql = self.discount.select("prices.item_id").to_sql
where("prices.discount_id IS NOT NULL OR prices.item_id NOT IN (#{discount_items_sql})")
end
end
This is effectively the same as this query:
SELECT * FROM prices
WHERE prices.discount_id IS NOT NULL -- the discount_id is present on this record,
OR prices.item_id NOT IN ( -- or no discount_id is present for this item
SELECT item_id FROM prices WHERE discount_id IS NOT NULL)
You can add these helper methods on your Item model for simplicity:
class Item < ActiveRecord::Base
def category_price
prices.category.first
end
def discount_price
prices.discount.first
end
def used_price
prices.used.first
end
end
Now you can easily get each individual 'type' of price for a single item (will be nil for prices that aren't available):
item.category_price
item.discount_price
item.used_price

Is it possible to merge two association tables in Sunspot solr

I have four tables. They are Brands, departments, categories and product_details. The models are
Brand model
class Brand < ActiveRecord::Base
has_many :product_details, :dependent=>:destroy
searchable do
integer :id
text :name
end
end
Deparment model
class Department < ActiveRecord::Base
has_many :product_details, :dependent=>:destroy
searchable do
integer :id
text :name
end
end
Category model
class Category < ActiveRecord::Base
has_many :product_details, :dependent=>:destroy
searchable do
integer :id
text :name
end
end
ProductDetail model
class ProductDetail < ActiveRecord::Base
belongs_to :department
belongs_to :category
belongs_to :brand
searchable do
text :name
text :brand do
brand.name
end
integer :department_id
integer :category_id
end
If user searches for department 1 first I have get all product details based on department id. The resultant table must contain brand name, category name and department name also. Is it possible to do it using sunspot solr? How?
I think you should create a Document for each Product with Brand, Department, Category and Product details.
Then you're able to search for what you want, and receive the information you need.

Rails 3 one-to-many relationship question - how to return column name value

I have a one-tomany relationship with 2 tables as follows:
Models:
class MediaType < ActiveRecord::Base
belongs_to :media
end
class Media < ActiveRecord::Base
has_many :media_types
end
SQL for simplicity sake are:
create_table :media do |t|
t.string "name", :limit => 255
t.integer "media_type_id"
end
create_table :media_types do |t|
t.string "name", :limit => 255
end
Once I insert a Media record relating to a media_type_id, how do I pull back the media_type.name value related to the media record?
I blindly tried:
media = Media.find(1)
media.media_type_id.name
But that didn't work of course. Is my SQL not Rails standards possibly?
Appreciate any help.
If you idea: media_type has many medias, but every media has only one media_type
You need another models:
class MediaType < ActiveRecord::Base
has_many :medias
end
class Media < ActiveRecord::Base
belongs_to :media_type
end
And
media = Media.find(1)
media.media_type.name
give you name
It seems that media has_many media_types.
In that case you would create media_id column in media_types table, but you did it other way around.
You will then approach each relation by
types = Media.media_types
to get the media_types that the Media has, and
media = MediaType.media
to get the media that mediatype belongs to.