Creating the Database schema

Part 4 of building a Rails 7 application

Rails provides scaffolds for generating all the boilerplate code for a Model in the application. This also includes the database migrations that will be needed.

These scaffolds are a little bit limited in what they support in terms of database migrations but will be a good enough start from which they can be customized.

I will not be going into too much detail about the structure of the database as it is not entirely relevant to this blogging exercise. Here are the relationship diagrams though.

image.png

image.png

An example scaffold result:

% rails generate scaffold ItemSellPack name:string canonical:boolean
      invoke  active_record
   identical    db/migrate/20220608092914_create_item_sell_packs.rb
   identical    app/models/item_sell_pack.rb
      invoke    test_unit
   identical      test/models/item_sell_pack_test.rb
   identical      test/fixtures/item_sell_packs.yml
      invoke  resource_route
       route    resources :item_sell_packs
      invoke  scaffold_controller
      create    app/controllers/item_sell_packs_controller.rb
      invoke    tailwindcss
      create      app/views/item_sell_packs
      create      app/views/item_sell_packs/index.html.erb
      create      app/views/item_sell_packs/edit.html.erb
      create      app/views/item_sell_packs/show.html.erb
      create      app/views/item_sell_packs/new.html.erb
      create      app/views/item_sell_packs/_form.html.erb
      create      app/views/item_sell_packs/_item_sell_pack.html.erb
      invoke    resource_route
      invoke    test_unit
      create      test/controllers/item_sell_packs_controller_test.rb
      create      test/system/item_sell_packs_test.rb
      invoke    helper
      create      app/helpers/item_sell_packs_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/item_sell_packs/index.json.jbuilder
      create      app/views/item_sell_packs/show.json.jbuilder
      create      app/views/item_sell_packs/_item_sell_pack.json.jbuilder

It is not possible to specify the default value of an attribute using the scaffold so to set canonical to be a default value of false that will require manually editing the generated file.

class CreateItemSellPacks < ActiveRecord::Migration[7.0]
  def change
    create_table :item_sell_packs do |t|
      t.string :name
      t.boolean :canonical, default: false

      t.timestamps
    end
  end
end

It also is not possible to specify json or jsonb as a type using the scaffolding so I'll need to manually set those too in the generated file.

class CreateTasks < ActiveRecord::Migration[7.0]
  def change
    create_table :tasks do |t|
      t.string :type
      t.integer :context_id
      t.string :context_type
      t.text :description
      t.jsonb :before
      t.jsonb :after
      t.string :status
      t.string :error
      t.boolean :requires_approval
      t.boolean :approved
      t.references :approved_by, foreign_key: true
      t.timestamp :approved_at

      t.timestamps
    end
  end
end

Another change to this file is the approved_by reference. By default these are set to null: false because all belongs_to associations are now assumed to be required. For my requirement though this is not the case so I need to remove that rule and also mark the association in the model as optional too.

class Action < ApplicationRecord
  belongs_to :approved_by, optional: true
end

Unfortunately the scaffolded code has many Rubocop violations as well. So I'll fix those using the auto correct.

% rubocop
...
154 files inspected, 1056 offenses detected, 1056 offenses autocorrectable
% rubocop -A

Now I can create the development and test databases. Back in Part 2 when I initialized the application it already created a default database.yml file. Nothing in there needs to be changed just yet so I can do the following.

% rails db:create
Created database 'catalogue_cleanser_development'
Created database 'catalogue_cleanser_test'
% rails db:migrate RAILS_ENV=test
== 20220608092914 CreateItemSellPacks: migrating ==============================
-- create_table(:item_sell_packs)
   -> 0.0102s
== 20220608092914 CreateItemSellPacks: migrated (0.0103s) =====================
% rails db:migrate
== 20220608092914 CreateItemSellPacks: migrating ==============================
-- create_table(:item_sell_packs)
   -> 0.0076s
== 20220608092914 CreateItemSellPacks: migrated (0.0077s) =====================
...

Finally I can start the application for the first time. I am using Rubymine so I need to add a new Run configuration to use Foreman as the server launcher. This will ensure that the TailwindCSS is compiled properly whenever a change is made.

First of all add Foreman to the Gemfile.

group :development do
  # Process manager
  gem 'foreman'
end

Then add a new Rubymine run configuration.

image.png

And now I have a running Rails 7 server.

image.png