"But… what about the model?" is a very common question from newcomers to
Mojolicious, and not everyone is happy with the simple answer: "You can
do whatever you want, Mojolicious doesn't care". What this really means
(especially for people coming from Catalyst) is that you can keep using
your DBIx::Class model with "use My::Model", or use whatever other
method you prefer to interact with your database.
I don't get along with DBIx::Class myself, but enough people ask about
using straight DBI that I felt it worthwhile to share the way I do it.
There's not much to it: my code boils down to calling DBI->connect
and keeping the handle for later use. Mojo's package attributes with
delayed initialisation make it easy to do this.
I put the following code in my startup function (i.e., sub startup in
lib/MyApp.pm):
sub startup {
my $app = shift;
# …read configuration and do other stuff…
(ref $app)->attr(
db => sub {
DBI->connect("dbi:Pg:database=$db", $user, $pass)
}
);
}
This adds a "db" attribute to my application class (represented here by
the $app object), which can be accessed as "$app->db". The first time
it is accessed, the function I provided is called, and its return value
is cached and returned as the value of the attribute thereafter. In this
case, my sub is a closure that uses the $db, $user, and $pass variables
read from the configuration file, and connects to a Postgres database
using DBI/DBD::Pg, but those are just details. You could do the same
thing with DBIx::Connector or a similar module.
(Aside: don't just create a database handle in startup. It will break if
you run your app under a preforking server like Hypnotoad. Your startup
will be called once before forking, but the DBI handle can't be shared
between the server processes. The delayed attribute initialisation is
perfect in this case, because each server will have its own handle.)
With this code, the database connection is created only the first time
it is needed, and it is kept around as long as the application is alive
(how long that is depends on which server your application runs under).
Controllers can just do "$self->app->db" to fetch a db handle at
any time without worrying about any of this.
Marcus Ramberg pointed out on
IRC that I could also use "$app->helper(db => sub {...})" to make
the handle accessible from controllers (as "$self->db") and from epl
templates (as "db"). I don't need to do that for database handles, but
someone else might find it useful.
(This is an old post that I forgot to submit when it was written.)