Initial commit for course branch

This commit is contained in:
niyas301 2025-11-18 14:25:22 +05:30
parent 4d1ede3531
commit ea11dc7a9c
14 changed files with 140 additions and 42 deletions

View File

@ -3,11 +3,17 @@ class CategoriesController < ApplicationController
# GET /categories or /categories.json
def index
@categories = Category.all
@categories = Category.includes(:products).all
@categories.each do |category|
category.products = category.products || []
end
end
# GET /categories/1 or /categories/1.json
def show
# `set_category` before_action will load @category; expose associated products as @products
@products = @category.products
end
# GET /categories/new
@ -60,7 +66,7 @@ class CategoriesController < ApplicationController
private
# Use callbacks to share common setup or constraints between actions.
def set_category
@category = Category.find(params.expect(:id))
@category = Category.find(params[:id])
end
# Only allow a list of trusted parameters through.

View File

@ -8,6 +8,8 @@ class ProductsController < ApplicationController
# GET /products/1 or /products/1.json
def show
@category = Category.find_by(id: params[:id])
@product = Product.find_by(id: params[:id])
end
# GET /products/new
@ -65,6 +67,6 @@ class ProductsController < ApplicationController
# Only allow a list of trusted parameters through.
def product_params
params.expect(product: [ :name, :description, :price, images: [] ])
params.require(:product).permit(:name, :category_id, :description, :price, images: [])
end
end

View File

@ -1,4 +1,6 @@
class Category < ApplicationRecord
has_rich_text :description
has_one_attached :image
# Use lowercase association name so ActiveRecord sets up `category.products`
has_many :products, dependent: :destroy
end

View File

@ -1,4 +1,6 @@
class Product < ApplicationRecord
has_rich_text :description
has_many_attached :images
belongs_to :category
end

View File

@ -1,8 +1,5 @@
<div id="<%= dom_id category %>">
<p>
<strong>Name:</strong>
<%= category.name %>
</p>
<h1><%= category.name %></h1>
<p>
<strong>Description:</strong>
@ -14,4 +11,14 @@
<%= link_to category.image.filename, category.image if category.image.attached? %>
</p>
</div>
<% if products.present? %>
<h2>Products in this Category</h2>
<ul>
<% products.each do |product| %>
<li><%= product.name %> - $<%= product.price %></li>
<% end %>
</ul>
<% else %>
<p>No products available in this category.</p>
<% end %>
</div>

View File

@ -6,7 +6,7 @@
<div id="categories">
<% @categories.each do |category| %>
<%= render category %>
<%= render partial: "category", locals: {category: category, products: category.products} %>
<p>
<%= link_to "Show this category", category %>
</p>

View File

@ -1,6 +1,6 @@
<p style="color: green"><%= notice %></p>
<%= render @category %>
<%= render partial: "category", locals: { category: @category, products: @products } %>
<div>
<%= link_to "Edit this category", edit_category_path(@category) %> |

View File

@ -53,8 +53,8 @@ html, body {
margin: 0;
padding: 0;
font-family: "Poppins", sans-serif;
background: linear-gradient(135deg, #0f1724, #1e293b);
color: #e6eef6;
background: #181a1b !important;
color: #0f1724;
}
.page-wrapper {
@ -65,7 +65,7 @@ html, body {
}
.container {
max-width: 1900px;
max-width: 100%;
margin: 0 auto;
padding-top: 20px;
flex: 1;

View File

@ -150,10 +150,50 @@ background: linear-gradient(-45deg, #1e88e5, #43a047, #6a1b9a, #d81b60);
.navbar {
position: fixed;
top: 0;
width: 100%;
width: 88%;
margin-left: 12%;
}
</style>
/* Sidebar styles */
.sidebar {
position: fixed;
top: 0; /* align under navbar */
left: 0;
bottom: 0;
width: 240px;
padding: 18px;
background: rgba(28,30,33,0.95);
color: #e6eef0;
border-right: 1px solid rgba(255,255,255,0.03);
z-index: 1040;
transition: transform .28s ease, width .2s ease;
overflow-y: auto;
}
.sidebar .side-logo { width:44px; height:44px; border-radius:8px; object-fit:cover; }
.sidebar .sidebar-brand { display:flex; align-items:center; gap:12px; margin-bottom:12px; }
.sidebar .brand-text { font-weight:700; color:#bfe6c8; font-size:1rem }
.sidebar .sidebar-toggle { margin-left:auto; background:transparent; border:none; color: #cfe9d8; font-size:1.1rem; cursor:pointer; }
.sidebar-nav ul { list-style:none; padding:0; margin:6px 0; }
.sidebar-nav li { margin:8px 0; }
.sidebar-nav a { color: #e6eef0; text-decoration:none; display:flex; gap:10px; align-items:center; padding:8px 10px; border-radius:8px; }
.sidebar-nav a:hover { background: rgba(30,136,229,0.12); color: #fff; }
/* Main content shift */
.main-container { margin-left: 0; transition: margin-left .28s ease; }
@media (min-width: 992px) {
.main-container { margin-left: 260px; }
}
/* Collapsed state */
.sidebar.collapsed { transform: translateX(-100%); }
@media (max-width: 991px) {
.sidebar { transform: translateX(-100%); }
.sidebar.open { transform: translateX(0); }
.main-container { margin-left: 0; }
}
</style>
<%# Includes all stylesheet files in app/assets/stylesheets %>
@ -178,27 +218,6 @@ background: linear-gradient(-45deg, #1e88e5, #43a047, #6a1b9a, #d81b60);
<!-- Nav Links -->
<div class="collapse navbar-collapse" id="mainNav">
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
<li class="nav-item">
<%= link_to "🏠 Home", root_path, class: "nav-link active" %>
</li>
<li class="nav-item">
<%= link_to "🎓 Programs", programs_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "🕌 Ziyara", ziyaras_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "📚 All Students", students_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "💰 Income", incomes_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "📊 Expenses", expenses_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "🏫 Records", exclusive_traditional_records_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "📞 Contact", contact_path, class: "nav-link" %>
</li>
@ -281,9 +300,29 @@ background: linear-gradient(-45deg, #1e88e5, #43a047, #6a1b9a, #d81b60);
<% content_for :title, "Institutions & Programs" %>
<!-- LEFT SIDEBAR -->
<aside class="sidebar" id="appSidebar" aria-label="Main navigation">
<div class="sidebar-brand">
<%= image_tag("unnamed.jpg", alt: "Logo", class: "side-logo") %>
<div class="brand-text">Badar Madeena</div>
<button class="sidebar-toggle" id="sidebarToggle" aria-label="Toggle sidebar">☰</button>
</div>
<nav class="sidebar-nav">
<ul>
<li><%= link_to "🏠 Home", root_path %></li>
<li><%= link_to "🎓 Programs", programs_path %></li>
<li><%= link_to "🕌 Ziyara", ziyaras_path %></li>
<li><%= link_to "📚 Students", students_path %></li>
<li><%= link_to "💰 Income", incomes_path %></li>
<li><%= link_to "📊 Expenses", expenses_path %></li>
<li><%= link_to "🏫 Records", exclusive_traditional_records_path %></li>
<li><%= link_to "📞 Products", products_path %></li>
</ul>
</nav>
</aside>
<% if flash.any? %>
<% if flash.any? %>
<% flash.each do |name, message| %>
<% if name.to_s == 'notice' || name.to_s == 'alert' %>
<div class="alert alert-<%= name.to_s == 'notice' ? 'success' : 'danger' %>">
@ -293,13 +332,31 @@ background: linear-gradient(-45deg, #1e88e5, #43a047, #6a1b9a, #d81b60);
<% end %>
<% end %>
<div class="container shadow rounded p-4 bg-white mt-4">
<%= yield %>
<div class="main-container">
<div class="container shadow rounded p-4 bg-white mt-4">
<%= yield %>
</div>
</div>
<footer class="footer text-center mt-5 mb-3 text-muted">
&copy; <%= Time.current.year %> Badar Madeena
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Sidebar toggle behavior
document.addEventListener('DOMContentLoaded', function () {
const toggle = document.getElementById('sidebarToggle');
const sidebar = document.getElementById('appSidebar');
if (toggle && sidebar) {
toggle.addEventListener('click', function () {
// For small screens toggle open class
if (window.innerWidth < 992) {
sidebar.classList.toggle('open');
} else {
sidebar.classList.toggle('collapsed');
}
});
}
});
</script>
</body>
</html>

View File

@ -16,6 +16,11 @@
<%= form.text_field :name %>
</div>
<div>
<%= form.label :category_id, "Category", style: "display: block" %>
<%= form.collection_select :category_id, Category.all, :id, :name, prompt: "Select Category" %>
</div>
<div>
<%= form.label :description, style: "display: block" %>
<%= form.rich_textarea :description %>

View File

@ -8,7 +8,12 @@
<strong>Description:</strong>
<%= product.description %>
</p>
<p>
<strong>Category:</strong>
<%= product.category.name if product.category %>
</p>
<p>
<strong>Images:</strong>
<% product.images.each do |image| %>

View File

@ -23,6 +23,10 @@ Rails.application.routes.draw do
resources :students
end
resources :categories do
resources :products
end
get "up" => "rails/health#show", as: :rails_health_check
get 'contact', to: 'institutions#contact'

View File

@ -0,0 +1,5 @@
class AddCategoryToProducts < ActiveRecord::Migration[8.0]
def change
add_reference :products, :category, null: true, foreign_key: true
end
end

5
db/schema.rb generated
View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_11_06_035813) do
ActiveRecord::Schema[8.0].define(version: 2025_11_06_132715) do
create_table "action_mailbox_inbound_emails", force: :cascade do |t|
t.integer "status", default: 0, null: false
t.string "message_id", null: false
@ -115,6 +115,8 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_06_035813) do
t.decimal "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id"
t.index ["category_id"], name: "index_products_on_category_id"
end
create_table "programs", force: :cascade do |t|
@ -159,5 +161,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_06_035813) do
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "products", "categories"
add_foreign_key "students", "institutions"
end