Getting started
Installation
Add the shard to your shard.yml
dependencies:
jennifer:
github: imdrasil/jennifer.cr
version: "~> 0.12.0"
For MySQL and PostgreSQL you need to add related driver shard - crystal-mysql or crystal-pg:
dependencies:
jennifer:
github: imdrasil/jennifer.cr
version: "= 0.12.0"
pg:
github: will/crystal-pg
version: "= 0.26.0"
# or for mysql
crystal-mysql:
github: crystal-lang/crystal-mysql
version: "= 0.14.0"
If you want to use SQLite3 - add Jennifer SQLite3 adapter:
dependencies:
jennifer:
github: imdrasil/jennifer.cr
version: "= 0.12.0"
jennifer_sqlite3_adapter:
github: imdrasil/jennifer_sqlite3_adapter
version: "~> 0.3.1"
It is shipped with SQLite driver.
In this tutorial we will be using PostgreSQL adapter.
Setting up database connection
Create ./config
folder - it will contain all your configurations. Also create ./config/initializers/database.cr
with following content:
require "jennifer"
require "jennifer/adapter/postgres" # for PostgreSQL
# require "jennifer/adapter/mysql" for MySQL
APP_ENV = ENV["APP_ENV"]? || "development"
Jennifer::Config.configure do |conf|
conf.read("config/database.yml", APP_ENV)
conf.from_uri(ENV["DATABASE_URI"]) if ENV.has_key?("DATABASE_URI")
conf.logger.level = APP_ENV == "development" ? :debug : :error
end
Log.setup "db", :debug, Log::IOBackend.new(formatter: Jennifer::Adapter::DBFormatter)
This allows you to put all database related configuration to structured yml file and override it with custom database connection URI passing it in DATABASE_URI
.
Now let’s create ./config/database.yml
:
default: &default
host: localhost
user: user_name
password: user_password
adapter: postgres
development:
<<: *default
db: application_database_name_development
test:
<<: *default
db: application_database_name_test
production:
<<: *default
db: application_database_name_production
NOTE: prefer creating shared database configuration file template rather than exact one (aka
database.example.yml
) so everyone can configure it for themselves.
Now create ./config/config.cr
which is responsible for loading all dependency’s configurations:
require "./initializers/**"
Translations
Jennifer under the hood use i18n for error message translation. Create ./config/locales/en.yml
for any custom translations and add ./config/initializers/zzz_i18n.cr
with following content:
I18n.load_path += ["./config/locales"]
I18n.init
CLI
To be able to use CLI install sam task manager and modify sam.cr
file in you application root folder with following content:
require "./your_configuration_folder/*" # here load jennifer and all required configurations
require "sam"
load_dependencies "jennifer"
# ...
Sam.help
Now you can invoke $ crystal sam.cr -- help
to get list of all available tasks. Also you can generate makefile shorthand for this - just invoke $ crystal sam.cr -- generate:makefile
. Now you are able to invoke Sam tasks by make
- $make sam help
.
Usage
First Models
We will use built-in generator to obtain our first model. Just create a folder ./src/models
for your models and invoke
$ make sam generate:model User name:string age:integer
This generates 2 files:
-
./src/models/user.cr
- files containing model definitionclass User < Jennifer::Model::Base with_timestamps mapping( id: Primary64, name: String, age: Int32, ) end
-
./db/migrations/<timestamp>_create_users.cr
- migration file (it is required to change your database schema)class CreateUsers < Jennifer::Migration::Base def up create_table :users do |t| t.string :title, {:null => false} t.integer :age, {:null => false} t.timestamps end end def down drop_table :users if table_exists? :users end end
Now you could add next lines at the bottom of your ./config/config.cr
require "../src/models/*"
This is optional; it depends how you would like to load your models - centralized or on demand.
Also you need to extend sam.cr
file:
require "./your_configuration_folder/*" # here load jennifer and all required configurations
require "sam"
require "./db/migrations/*"
load_dependencies "jennifer"
# ...
Sam.help
To be able to use our new model we need to populate schema changes to the database. For this invoke next commands:
$ make sam db:create
- this creates a new database (should be invoked only once at setup stage);$ make sam db:migrate
- invokes all pending migrations.
Now we are able to use our model:
user = User.create({name: "New User", age: 100})
puts user.inspect