Connect DB to a Ruby Project and play with queries in console

I already had a ruby project, and there are few things I wanted to try to test some ActiveRecord queries. First I implemented a small script (see here ) But it was not easy to play with classes as I had to run the full script (gem install, models definitions etc.).

I was looking a way to interact directly with the dabase in console.

Models

I had 4 different models in my ruby app:

  1. location
  2. role
  3. person
  4. region

defined like so:

class Location < ActiveRecord::Base
  belongs_to :region
  has_many :people
end

class Person < ActiveRecord::Base
  belongs_to :location
  belongs_to :role
  belongs_to :manager, class_name: "Person", foreign_key: :manager_id
  has_many :employees, class_name: "Person", foreign_key: :manager_id
end

class Region < ActiveRecord::Base
  has_many :locations
end

class Role < ActiveRecord::Base
  has_many :people
end

Gemfile

source "https://rubygems.org"

ruby "2.5.3"

gem "activerecord"
gem "byebug"
gem "database_cleaner"
gem "factory_girl"
gem "pg"
gem "pry"
gem "rake"
gem "rspec"

What we see in this gemfile is:

  • activerecord gem is already present
  • I used pg, but one can choose any database

to this Gemfile I had this gem

gem 'standalone_migrations'

This gem provide a way to run Rails migrations in non-Rails (and non Ruby) projects.

To install the gem I ran in console:

$ bundle install

Configuration

The 'standalone_migrations' comes with a setup.

  1. The first step was to create a file config.yml in db directory:
default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5
  host: localhost

development:
  <<: *default
  database: has_many_development
  1. Then, I added this in the Rakefile
require 'standalone_migrations'
StandaloneMigrations::Tasks.load_tasks
  1. I checked I had access to the rake tasks with:
$ bundle exec rake --tasks

Database

I started by creating the database:

$ bundle exec rake db:create
Created database 'has_many_development'

Then I made the migration to create the schema:

$ bundle exec rake db:new_migration name=create_roles
      create  db/migrate/20181113182825_create_roles.rb

I went to the file 20181113182825_create_roles in db/migrate directory and adapt the table:

class CreateRoles < ActiveRecord::Migration[5.2]
  def change
    create_table :roles do |t|
      t.string :name
      t.boolean :billable
    end
  end
end

Then I ran the bundle exec rake db:migrate

bundle exec rake db:migrate
== 20181113182825 CreateRoles: migrating ======================================
-- create_table(:roles)
   -> 0.0515s
== 20181113182825 CreateRoles: migrated (0.0516s) =============================

I repeted this to create my 3 other tables. To finally have this schema:

ActiveRecord::Schema.define(version: 2018_11_13_184450) do

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

  create_table "locations", force: :cascade do |t|
    t.bigint "role_id"
    t.string "name"
    t.index ["role_id"], name: "index_locations_on_role_id"
  end

  create_table "people", force: :cascade do |t|
    t.bigint "location_id"
    t.string "name"
    t.integer "salary"
    t.bigint "role_id"
    t.index ["location_id"], name: "index_people_on_location_id"
    t.index ["role_id"], name: "index_people_on_role_id"
  end

  create_table "regions", force: :cascade do |t|
    t.string "name"
  end

  create_table "roles", force: :cascade do |t|
    t.string "name"
    t.boolean "billable"
  end

end

Then after having doing this, I can check my tables with $ psql -d has_many_development -c "\d+ roles" in console.

The last word is a way of specifying which table we are talking about.

                                                      Table "public.roles"
  Column  |       Type        | Collation | Nullable |              Default              | Storage  | Stats target | Description
----------+-------------------+-----------+----------+-----------------------------------+----------+--------------+-------------
 id       | bigint            |           | not null | nextval('roles_id_seq'::regclass) | plain    |              |
 name     | character varying |           |          |                                   | extended |              |
 billable | boolean           |           |          |                                   | plain    |              |
Indexes:
    "roles_pkey" PRIMARY KEY, btree (id)

Connecting to Database

Then, I launched an irb console and I used these commands to access to the db:

>> require 'active_record'
>> require_relative './app/models/role'

>> db_configuration_file_path = '....../db/config.yml'
>> db_configuration = YAML.load(File.read(db_configuration_file_path))

>> ActiveRecord::Base.establish_connection(db_configuration["development"])

db_configuration_file_path being the path to the config file.

Then I could direcly create records:

>> Role.create(name: 'role1', billable: true)
#<Role id: 1, name: "role1", billable: true>
>> Role.all
#<ActiveRecord::Relation [#<Role id: 1, name: "role1", billable: true>]>

☀️ I can now leave the project and come back later. I don’t need to recreate new records as the data are persisted in DB.

The only thing when coming back is to establish the connection to the DB, so we have to run the above script:

>> require 'active_record'

>> db_configuration = YAML.load(File.read("../db/config.yml"))
>> ActiveRecord::Base.establish_connection(db_configuration["development"])

The trap is not to forget to require models, so we can play with them.

>> require_relative './app/models/region'
true
>> Region.all
#<ActiveRecord::Relation [#<Region id: 1, name: "region1">, #<Region id: 2, name: "Bretagne">]>

If we don’t require_relative, we get:

>> Location.all
Traceback (most recent call last):
        2: from /Users/cco/.rvm/rubies/ruby-2.5.3/bin/irb:11:in `<main>'
        1: from (irb):10
NameError (uninitialized constant Location)

Notes

To navigate into PG:

// open pg console
$ psql postgres

// list all databases
\list

// change database
\c name_of_the_db

// to open a connection straight in console
>> require 'pg'
true
>>  conn = PG::Connection.open(:dbname => 'has_many_development')
#<PG::Connection:0x00007fe586a29cc0>

To query data stores, I used Postico.


sources: This article + StackOverflow :)

gist: Coming from my gist


next steps

  • see how I can seed it straight from a db/seed.rb and access the db via the console

Updated: