Reputation: 721
I have 3 models
belongs_to: :product
has_many: :sizes
and that belongs_to: :category
has_many: :products
I want sort them in a table in my Products index by Category title, then by product title, then by size
Caegories | Product | Size |
----------------------------
A | A | S |
A | A | M |
A | B | S |
A | C | S |
B | A | S |
B | A | M |
B | B | S |
B | C | S |
How I am supposed to chain and order all this? is it possible?
update
create_table "categories", force: :cascade do |t|
t.string "title", limit: 100, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.string "title", limit: 150, null: false
t.decimal "price", precision: 15, scale: 2, default: "0.0", null: false
t.text "description"
t.bigint "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "color"
t.integer "user_id"
t.json "attachments"
t.index ["category_id"], name: "index_products_on_category_id"
end
create_table "sizes", force: :cascade do |t|
t.string "size_name"
t.integer "quantity"
t.bigint "product_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["product_id"], name: "index_sizes_on_product_id"
end
I think I'd rather start ordering from Size in order to display each size... But I dont know how...
index.html.erb
<% "my query???".each do |size| %>
<td><%= size.product.category.title %></td>
<td><%= size.product.title %></td>
<td><%= size.product.price %></td>
<td><%= size.size_name %></td>
<td><%= size.quantity %></td>
<% end %>
Upvotes: 1
Views: 38
Reputation: 12203
While @ray's answer is solid for the most part, I think you'll need to plug in something extra to get the sizes ordered as expected, i.e. 'small, medium, large'.
In ray's answer, this would be alphabetical, while I imagine you'd want this to be from small to large or vice versa.
This would make your query look something like the following:
Product.joins(:category, :sizes).order("categories.title, title").order("CASE sizes.size_name WHEN 'SMALL' THEN 'a' WHEN 'MEDIUM' THEN 'b' WHEN 'LARGE' THEN 'c' ELSE 'z' END ASC")
I've chained order
separately for the CASE
statement for readability, though you could also do something like:
Product.joins(:category, :sizes).order("categories.title, title, CASE sizes.size_name WHEN 'SMALL' THEN 'a' WHEN 'MEDIUM' THEN 'b' WHEN 'LARGE' THEN 'c' ELSE 'z' END ASC")
Personally speaking, I'd go a step further with this and store the sizes as an enum
column in the db if at all possible:
enum size_name: [:small, :medium, :large]
# Or enum size_name: { small: 0, medium: 1, large: 2 }
This makes the code very simple as the enum column stores an integer in order of the above:
Product.joins(:category, :sizes).order("categories.title, title, sizes.size_name")
Finally, this has bonus points: you'll have access to methods such as Size.medium
, size.medium?
, size.large!
and so on :)
Hope this helps - let me know if you've any questions or comments!
Edit based on update to question
To start with the Size
, you would tweak to one of the following:
Size.joins(product: :category).order("CASE sizes.size_name WHEN 'SMALL' THEN 'a' WHEN 'MEDIUM' THEN 'b' WHEN 'LARGE' THEN 'c' ELSE 'z' END ASC").order("categories.title, products.title")
Or with enum
:
Size.joins(product: :category).order("sizes.size_name, categories.title, products.title")
Upvotes: 2
Reputation: 5552
I did not test following but must work,
I did not get your sizes
table schema properly. Assuming Size
model have column type
to store values like L(large), S(small) & M(medium).
Product.joins(:category, :sizes).order('categories.title, title, sizes.type')
Make sure your associations and table schema are proper
Note: AS per your updated schema,
Product.joins(:category, :sizes).order('categories.title, title, sizes.size_name')
Upvotes: 2