Industrial-Grade Codebase: Setting up Data Tables with Devise, Scaffolds, Models
Published: 2023-10-24 16:38:02

We are writing industrial-grade code to learn about building up a project from scratch in Ruby on Rails. This blog post will serve as a reference for future projects and attempt to compile and understand what we have learned so far.

For the users table, we're using Devise, one of the most popular authentication GEMS (?) in Rails.

Gem groups allows us to specify gems we want to use in development, production, or all of the time. By compartmentalizing gems like this, it saves memory to not load all the gems all of the time.

We first add `gem "Devise"` and then `bundle install` and `rails generate devise:install` to complete the installation process for Devise. We then have to follow the steps Devise requires in order to use it. The first is defining a root route in the controller.

Once this is taken care of, we generate the users table using `rails g devise user username private:boolean likes_count:integer comments_count:integer`. Keep in mind string is the default datatype so we can leave that off as is the case with defining username above.

We also then change username and email to citext in our migration. This stands for case-insensitive text and means the column will not be case sensitive thus ensuring you can't have the same username as someone else but with different capitalization, for instance. Don't forget to add the line `enable_extension("citext")` at the top of your migration to use this. This datatype is a feature of PostgreSQL.

Some things devise does:
-It has steps for handling a forgotten password built in
-It has a bunch of pregenerated columns you can add in to track different user data or activity
-It adds the line `add_index :users, :email, unique: true`. This speeds up lookups. Otherwise you would have to scan through the entire database to find what you're looking for.  Devise does it automatically for email and a good idea to add  index for usernames as well since you look users up by username frequently. Adding `unique: true` adds a database-level check for enforcing uniqueness. On rare cases regular validations may fail so the uniqueness enforcement will be stronger with the added fortification of a database-level check. Also, primary keys are indexed automatically so this isn't necessary for those columns.

For things with a count set a default value, such as likes_count and comment_count. These should generally be initialized to zero. If you don't set a default value, Devise's default is a nil value which can cause issues.

Once the migration is all set up run `rake db:migrate` and your users table is good to go. (If you have issues run `rake db:drop` then `rake db:create` to set up your database.)

**Setting up the rest of your data tables**

When you're setting up the rest of the tables figure out if it's better to generate a scaffold or a model for each. In general, if your users need to be able to commit CRUD functions in your app, use scaffold. If the model will only be used by other models in the backend, use model.

Delete the `null: false` option in a column if you want it to have the option of being blank.

Don't forget to update all your associations if you want to use more descriptive foreign key column names than convention.

You will have to use `to_table` to clarify the table name the foreign key points to when deviating from convention as well. That looks like this:

`t.references :owner, null: false, foreign_key: { to_table: :users }`