Awesome
Example Glimmer DSL GUI app using ActiveRecord
This repository was originally created to satisfy my need for a kind of
boilerplate using Glimmer DSL with
ActiveRecord
as an ORM over a sqlite3
database. At that time, I couldn't
find any resources on it. Since then, Andy
Maleh, OSS Author of
Glimmer, reached out to me about his
post, Using ActiveRecord with SQLite DB in a JRuby Desktop
App.
I decided to put together a tutorial to extend this idea further, including
other migration tasks from ActiveRecord::Tasks::DatabaseTask
, and an ability
to run rake db:seed
using the SeedLoader
.
If you'd like to use this repository, just follow Setup. Otherwise, follow the ALTERNATIVE APPROACH.
Setup
- Clone repository
- Install dependencies:
bundle install
- Prepare database:
rake db:prepare
- Run app:
glimmer run
ALTERNATIVE APPROACH
Without using this repository, just follow along with this tutorial.
Table of Contents
- Install Glimmer
- Scaffold a Glimmer demo app
- Commit remaining scaffolding
- Add dependencies
- Install dependencies
- Add db directory
- Add migration for contacts table
- Add database configuration
- Add a SQLite database with ActiveRecord
- Integrate DatabaseTasks with SeedLoader
- Add rake tasks for ActiveRecord migrations
- Wire up ActiveRecord tasks in Rakefile
- Verify rake tasks
- Prepare database
- Add Contact model
- Add seed data
- Import seed data
- Update demo view
- Run demo app
- Troubleshooting
Install Glimmer
See instructions at glimmer-dsl-libui
Scaffold a Glimmer demo app
glimmer "scaffold[demo]"
cd demo
Commit remaining scaffolding
This step is optional.
Glimmer makes an initial git commit and leaves a dirty tree, so to clean it up...
git add .
git commit -m "Add remaining scaffolding"
Add dependencies
after gem 'glimmer-dsl-libui'
line
# Gemfile
gem 'activerecord', '~> 7.1', '>= 7.1.3.4'
gem 'sqlite3', '~> 1.4', force_ruby_platform: true
Install dependencies
bundle install
Add db directory
mkdir -p db/migrate
Add migration for contacts table
touch db/migrate/20240708135100_create_contacts.rb
# db/migrate/20240708135100_create_contacts.rb
require 'active_record'
class CreateContacts < ActiveRecord::Migration[7.1]
def change
create_table :contacts do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :phone
t.string :street
t.string :city
t.string :state_or_province
t.string :zip_or_postal_code
t.string :country
end
end
end
Add database configuration
mkdir config
touch config/database.yml
# config/database.yml
default: &default
adapter: sqlite3
pool: 5
timeout: 5000
development:
<<: *default
database: db/demo.sqlite3
test:
<<: *default
database: db/test.sqlite3
Add a SQLite database with ActiveRecord
Add shared methods for database access
touch db/config.rb
# db/config.rb
class Demo
module DB
module Config
def root
File.expand_path('../..', __FILE__)
end
def file
File.join(root, "config/database.yml")
end
def yaml
# aliases: true fixes Psych::AliasesNotEnabled exception
YAML.load_file(file, aliases: true)
end
def env
ENV['ENV'] || 'development'
end
end
end
end
Add database connection
touch db/connection.rb
# db/connection.rb
require 'active_record'
require_relative './config'
include Demo::DB::Config
ActiveRecord::Base.configurations = Demo::DB::Config::yaml
ActiveRecord::Base.establish_connection(Demo::DB::Config::env.to_sym)
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
Integrate DatabaseTasks with SeedLoader
mkdir support
touch support/active_record_rake_tasks.rb
Add rake
tasks for ActiveRecord migrations
# support/active_record_rake_tasks.rb
require_relative '../db/connection'
include ActiveRecord::Tasks
root = Demo::DB::Config::root
DatabaseTasks.root = root
DatabaseTasks.db_dir = File.join(root, 'db')
DatabaseTasks.migrations_paths = [File.join(root, 'db/migrate')]
DatabaseTasks.database_configuration = Demo::DB::Config::yaml
# The SeedLoader is Optional, if you don't want/need seeds you can skip setting it
class SeedLoader
def initialize(seed_file)
@seed_file = seed_file
end
def load_seed
load @seed_file if File.exist?(@seed_file)
end
end
DatabaseTasks.seed_loader = SeedLoader.new(File.join(root, 'db/seeds.rb'))
DatabaseTasks.env = Demo::DB::Config::env
load 'active_record/railties/databases.rake'
Wire up ActiveRecord tasks in Rakefile
# Rakefile
require './support/active_record_rake_tasks'
Verify rake tasks
rake -T
Add fix for "Don't know how to build task 'environment'" error
# Rakefile
Rake::Task.define_task(:environment)
Prepare database
rake db:prepare
Add Contact model
touch app/demo/model/contact.rb
# app/demo/model/contact.rb
class Contact < ActiveRecord::Base
end
Add seed data
touch db/seeds.rb
touch db/models.rb
# db/models.rb
model_dir = File.expand_path('../../app/demo/model', __FILE__)
Dir.glob(File.join(model_dir, '**', '*.rb')).each { |model| require model }
# db/seeds.rb
require 'active_record'
require_relative './connection'
require_relative "./models"
Contact.create(first_name: 'Chip',
last_name: 'Castle',
email: 'chip@chipcastle.com',
phone: '555-555-5555',
street: 'Any street',
city: 'Inlet Beach',
state_or_province: 'FL',
zip_or_postal_code: '55555',
country: 'US')
Import seed data
rake db:seed
Update demo view
At the top of the file, replace the require 'demo/model/greeting'
with:
# app/demo/view/demo.rb
require 'demo/model/contact'
Inside the before_body
block, replace @greeting = Model::Greeting.new
with:
@contact = Contact.first
Inside def launch
method (after margined true
line), remove the reference
to the @greeting
form
entry
and add the following code to verify
ActiveRecord:
vertical_box {
form {
stretchy false
entry {
label 'First name'
text <=> [@contact, :first_name]
}
entry {
label 'Last name'
text <=> [@contact, :last_name]
}
entry {
label 'Email'
text <=> [@contact, :email]
}
entry {
label 'Phone'
text <=> [@contact, :phone]
}
entry {
label 'Street address'
text <=> [@contact, :street]
}
entry {
label 'City'
text <=> [@contact, :city]
}
entry {
label 'State/Province'
text <=> [@contact, :state_or_province]
}
entry {
label 'Zip/Postal code'
text <=> [@contact, :zip_or_postal_code]
}
entry {
label 'Country'
text <=> [@contact, :country]
}
}
}
Run demo app
glimmer run
Troubleshooting
- If you encounter a
Don't know how to build task environment
error, try adding this to the bottom of yourRakefile
:
# Rakefile
Rake::Task.define_task(:environment)
- When an ActiveRecord::EnvironmentMismatchError exception is raised, run this from the shell:
rake db:environment:set ENV=development
- Running
rake db:version
raises anNameError: uninitialized constant Rails (NameError)
exception, which can be fixed with this hack (open to other suggestions, but I gotta move on.)
# Rakefile
class Rails
def env
ENV['ENV'] || 'development'
end
end
Copyright
Copyright (c) 2024 Chip Castle. See LICENSE for further details.
<!-- [SeedLoader example](https://jeremykreutzbender.com/blog/add-active-record-rake-tasks-to-gem) [Testing Rake task with Rspec with Rails environment](https://stackoverflow.com/questions/12686282/testing-rake-task-with-rspec-with-rails-environment) (via StackOverflow - Winston Kotzan's answer) -->