DEV Community

Szechuan SaaS
Szechuan SaaS

Posted on • Updated on

How to manage your Ruby on Rails project deployed on Heroku

Staring at a blank VS code editor can be intimidating when approaching a new project and I'll be sharing some helpful tricks that I used to maximize my productivity for my attendance management app.

The primary functionality of this app goes as follows:

  1. Users will be able to manage attendance for each lecture.
    Once logged in the user will view the available lectures to the Teacher.

  2. Then after clicking the "Attendance log" under the lecture users will then have the ability to log attendance for the lecture with CRUD functionality.

  3. Users will have sign in / out capability.

  4. Users will only be able to view their own students unless they are an admin user.

Productivity Setup

I utilized notion as a primary source for managing my project listing my requirements and hosting my diagrams as well as any note taking with documentation I read during building my web app. I also created a Entity relationship diagram illustrate the relationships of my schema which you can see below:

Listing out requirements in notion

Image description

Entity Relationship Diagram

Image description

Schema

ActiveRecord::Schema.define(version: 2021_11_05_185536) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "attendances", force: :cascade do |t|
    t.string "student_name"
    t.integer "student_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.bigint "user_id"
    t.string "status"
    t.bigint "lectures_id"
    t.index ["lectures_id"], name: "index_attendances_on_lectures_id"
    t.index ["user_id"], name: "index_attendances_on_user_id"
  end

  create_table "lectures", force: :cascade do |t|
    t.string "name"
    t.string "description"
    t.integer "classroom_number"
    t.time "duration"
    t.bigint "user_id"
    t.index ["user_id"], name: "index_lectures_on_user_id"
  end

  create_table "students", force: :cascade do |t|
    t.string "student_name"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.bigint "lectures_id"
    t.bigint "user_id", null: false
    t.index ["lectures_id"], name: "index_students_on_lectures_id"
    t.index ["user_id"], name: "index_students_on_user_id"
  end

  create_table "teachers", force: :cascade do |t|
    t.string "teacher_name"
    t.string "teacher_type"
    t.bigint "user_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["user_id"], name: "index_teachers_on_user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.string "provider"
    t.string "uid"
    t.string "name"
    t.integer "role", default: 0
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

  add_foreign_key "attendances", "lectures", column: "lectures_id"
  add_foreign_key "students", "lectures", column: "lectures_id"
  add_foreign_key "students", "users"
end
Enter fullscreen mode Exit fullscreen mode

Ruby on Rails naming conventions

Here is a consolidated list of Naming Conventions in Ruby on Rails, that I have collected from the internet. I'm highlighting this because when you are creating your associations it's important to have the correct pluralization, otherwise your relationships between models will not work correctly.

Model -
Follows the convention of Class names of unbroken MixedCase letters
Always Singular format of the corresponding Table Name in database
file name for the Models should always be in lowercase. For Multiple words use '_'
eg.: Order (table name: orders | file name: /app/models/order.rb )

Database Table -
Table names have all lowercase letters and underscores between words, also all table names need to be plural
e.g. invoice_items, orders

Files & Directories -
Files and Directories are named using lowercase letters and '_' for multiple words formats
Proper naming and pluralization is mandatory for the conventional functioning of Rails
eg.: app/helpers/orders_helper.rb, app/models/order.rb

Creating migration associations

When you create an association, Rails makes two major assumptions – first, that the class of the model your association points to is based directly off of the name of the association, and, second, that the foreign key in any belongs_to relationship will be called yourassociationname_id. Any time you go away from these defaults, you just need to let Rails know what kind of class to look for and which foreign key to use. This especially was useful in building my user table / model and acknowledging only my teacher and admin roles.

Teachers using the attendy web app will only be able to view their own lectures and students. I was able to setup functionality in the lectures controller

class LecturesController < ApplicationController
  before_action :set_lecture, only: %i[ show edit update destroy ]

  # GET /lectures or /lectures.json
  def index
    if current_user == nil
      redirect_to users_sign_in_path
    else
      @lectures = Lecture.teachers_lectures(current_user)
    end
  end
Enter fullscreen mode Exit fullscreen mode

In the code above I edited the index function. I first created a conditional to check if the user is signed in and if the user is signed in to use a lambda function current_user to check the current user. These relationships would not be possible if I could lectures did not belong to user, a nested attribute. See code snippet below:

class Lecture < ApplicationRecord
    has_many :attendances, dependent: :destroy, foreign_key: :lectures_id
    belongs_to :user
    validates :name, presence: true
    scope :teachers_lectures, -> (user) { where(user_id: user.id) }
    accepts_nested_attributes_for :attendances
end
Enter fullscreen mode Exit fullscreen mode

Creating different Roles

If your app consist of utilizing multiple user types, chance are you are going to want to assign them different roles to allow and restrict access to certain functions. I only decided to give teachers access to this attendance app and have them log students into the portal. I assigned my users the role teacher and admin using the attribute enum. enum is an attribute where the values map to integers in the database and can be queried by name. See code snippet below.

class User < ApplicationRecord
  enum role: {Teacher: 0, Admin: 1}
  has_many :students

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  accepts_nested_attributes_for :students
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:google_oauth2]


  def self.from_omniauth(auth)
    where(email: auth.info.email).first_or_initialize do |user|
      user.email = auth.info.email
      user.password = user.password_confirmation = SecureRandom.hex
    end

  end
end
Enter fullscreen mode Exit fullscreen mode

I decided to deploy my app to Heroku and if you would like to deploy your app to Heroku please feel free to check out some documentation /here

You can view my app live /here!

Top comments (0)