This is step one of a walkthrough for building a new app with rom-rails
. I’ll talk about my justifications and philosophy in another post; my intention here is to walk through the initial creation of a rom-rails
application.
The end goal of this application is to serve as a file repository for use with another site. As I work throgh building the app, I’ll list out followons for some specific subjects of interest. This post highlights the initial generation and through to pulling some ‘hello world’ content from a data store.
Some things will look simliar to the normal rails setup, but there are some variations that I’ll be illuminating here. As I’ve worked with Ruby and Rails for a long, long time, I (like Rails itself) Have Opinions, and since this is my blog, I’ll not be shy about sharing them. Hopefully, some of that will serve as jumping off points for posts I’ve been meaing to write for ages.
Step the first: Generation
The stock Rails generator is what we’ll use here, with a few options specified:
flip@kona:~/src$ rails new rom-rails-demo --skip-active-record --skip-spring --skip-coffee --skip-test
create
create README.md
create Rakefile
# ... gobs of output elided
flip@kona:~/src$ cd rom-rails-demo/
flip@kona:~/src/rom-rails-demo (master #)$ git add .
flip@kona:~/src/rom-rails-demo (master +)$ git commit -m 'initial app generation'
I’ve skipped activerecord for what I hope are obvious reasons. coffeescript
has never been a JS flavor I’m wild about, and I suspect there are better
options these days. I’ve skipped minitest so that I can install rspec.
Skipping spring
is a big one. I consider it a band-aid that often causes more
problems than it helps with. ROM’s interctions with rails
autoloading is
still finiky at best, and adding another layer of load confusion … as
maintainer of rom-rails
, I’ve done basically nothing to support spring
. If
it’s a thing you need, contributions are encouraged.
We now have an intial app generated. At present, it’s nothing a web router and renderer; we have no storage, and no tests (because rails won’t generate rspec installs). Let’s fix that:
gem "pg"
gem "rom-rails"
gem "rom-sql"
gem "rom-repository"
group :development, :test do
gem "dotenv-rails"
gem "rspec-rails", "~> 3.0"
end
-
dotenv
is useful for loading environment variable configurations from configuration files; we’ll use it in development and test to configure things, while production will have to rely on real environment configurations. -
rspec-rails
because I have strong affinity for rspec’s testing philosophies, and every test::spec suite I’ve ever seen has expended great effort on reinventing things from rspec, poorly. -
pg
because postgres. We’re going to be using some embedded JSON down the way, and postgres makes this easy to work with. Ordinarily, the rails generator allows you to specify via-d postgres
but since we--skip-active-record
, the rails installer ignores our database preference. -
rom-rails
gives us basic rom dependencies, integration with rails, and a few handy generators. It does not assume which backends we’re going to use, and so: -
rom-sql
implements an SQL adapter and relation, which we will use to access our database. There are other adapters available, covering things from cassandra to yaml to REST api calls. At first, we’re simply interested in our database. -
rom-repository
implements a nicer interface on top of the rom relation backends. Repositories serve as a fantastic place to translate between your storage implementations and the language of your domain.
We’ll finish off the gem installations by generating our rspec configuration and comitting:
flip@kona:~/src/rom-rails-demo (master)$ bin/rails g rspec:install
create .rspec
create spec
create spec/spec_helper.rb
create spec/rails_helper.rb
Configuring rom-rails
The next part is, unfortuntely, very twitchy. Ordering is important, or exceptions will be thrown.
First, ensure your databases have been created. I’m going to wave the flag and call configuring your postgres install out of scope for this tutorial; at the end, you want to have both a test and development instance accessible.
Here’s the commands I threw locally:
flip@kona:~/src/rom-rails-demo (master)$ createdb rom_rails_demo_development
flip@kona:~/src/rom-rails-demo (master)$ createdb rom_rails_demo_test
Next, we’ll add some environment configuration:
# .env.development
DATABASE_URL=postgres://localhost/rom_rails_demo_development
# .env.test
DATABASE_URL=postgres://localhost/rom_rails_demo_test
rom-sql
generally prefers to use a connection_uri string for determining
how to connect to your database. If you specified a username and password
then the string will look more like: postgres://user:pass@localhost/rom_rails_demo_development
To access migration generators1, add this line to your rakefile:
# Rakefile
require "rom/sql/rake_task"
The migration syntax is using the Sequel
gem; nothing changes from there.
Finally, we generate our configurations and commit:
flip@kona:~/src/rom-rails-demo (master)$ bin/rails g rom:install
create config/initializers/rom.rb
create lib/types.rb
create app/models/application_model.rb
This last step generates the configurations necessary to tell rom about it’s
database gateways. The generator could be smarter; at the moment,
it assumes that there is an sql
adapter loaded and that you’d like for
it to be the default gateway. config/initializers/rom.rb
is the file to edit
if you are adding additional gateways, or if you need to set any additional
configurations.
Finally, we can verify see if everything is wired by running our specs:
flip@kona:~/src/rom-rails-demo (master +)$ bundle exec rspec -rrails_helper
No examples found.
Finished in 0.00039 seconds (files took 1.3 seconds to load)
If everything has been wired correctly, and the database exists, than the specs
will run. If an exception is thrown, then either ROM does not know where the
database can be found (check your .env
s) or the database does not exist.
Adding Profiles
As a final step, we’re going to add a profiles table to the database, add some content to it, and display it in a barebones controller.
First, we create the migration:
flip@kona:~/src/rom-rails-demo (master)$ bin/rails db:create_migration[create-profiles]
<= migration file created db/migraate/20180413141632_create-profiles.rb
flip@kona:~/src/rom-rails-demo (master)$
This creates a new migration file in the familiar timestamped form. The syntax
of the migration comes from Sequel
:
ROM::SQL.migration do
change do
create_table :profiles do
primary_key :id
column :email, String, null: false, unique: true, index: true
column :display_name, String
column :private_email, TrueClass, default: true
column :bio, :text
column :state, String, default: 'active', index: true
end
end
end
running the familiar rake db:migrate
will create our table.
Now, let’s generate a relation and a repository so we can access the table:
flip@kona:~/src/rom-rails-demo (master)$ be rails g rom:relation profiles
create app/relations/profiles_relation.rb
flip@kona:~/src/rom-rails-demo (master)$ bin/rails g rom:repository profiles
create app/repositories/profile_repository.rb
flip@kona:~/src/rom-rails-demo (master)$
Now if we crack open the console, we’ll be able to add some quick test data to the table:
irb(main):001:0> profiles = ProfileRepository.new(ROM.env)
=> #<ProfileRepository struct_namespace=rom-rails-demo auto_struct=true>
irb(main):004:0> profiles.create([
{email: '[email protected]', display_name: "Test Guy"},
{email: '[email protected]', display_name: "Old profile", state: 'disabled'}
])
=> #<rom-rails-demo::Profile id=1 email="[email protected]" display_name="Test Guy" private_email=true bio=nil state="active">
irb(main):005:0> ROM.env.relations[:profiles].count
=> 2
irb(main):006:0>
By default, there are no reader methods defined in a repository; we want to tune those specficially for our project domain, something I will go over in a later post.
Next steps
This is the bare bones; The initial app configuration is done, but there is not yet anything useful going on. In the next step, we’re going to demonstrate commands by adding authentication to the application.
-
I definatly need to fix this in the rom-rails code; it should be part of the normal installation, or even pushed into the “normal” generator flow. ↩