Reputation: 1364
I need to run Diesel database migrations in production for a Rocket-based app. Generally there are to ways to perform migrations for the database:
I prefer the second option that would be invoked by using the --migrate
flag for the application binary, but as the target application is fairly simple the first way will do just fine.
There is a thread in the Diesel issue tracker about running migrations in production and advise on how to do it:
- Add
diesel_migrations
to your dependencies- Include an
extern crate diesel_migrations
in your crate, and make sure to decorate it with#[macro_use]
- At the beginning of your code, add
embed_migrations!()
- To run the migrations, Use
embedded_migrations::run(&db_conn)
In main.rs
I made:
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
#[database("my_db_name")]
pub struct DbConn(diesel::PgConnection);
fn main() {
// Update database
embed_migrations!();
embedded_migrations::run(&DbConn);
// Launch the app
...
}
This leads to the error:
error[E0277]: the trait bound `fn(diesel::r2d2::PooledConnection<<diesel::PgConnection as rocket_contrib::databases::Poolable>::Manager>) -> DbConn {DbConn}: diesel::Connection` is not satisfied
--> src/main.rs:30:30
|
29 | embed_migrations!();
| --------------------
| |
| required by this bound in `main::embedded_migrations::run`
30 | embedded_migrations::run(&DbConn);
| ^^^^^^^ the trait `diesel::Connection` is not implemented for `fn(diesel::r2d2::PooledConnection<<diesel::PgConnection as rocket_contrib::databases::Poolable>::Manager>) -> DbConn {DbConn}`
|
= note: required because of the requirements on the impl of `diesel_migrations::MigrationConnection` for `fn(diesel::r2d2::PooledConnection<<diesel::PgConnection as rocket_contrib::databases::Poolable>::Manager>) -> DbConn {DbConn}`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
How to fix it?
Upvotes: 3
Views: 4036
Reputation: 1707
Building off of SS_Rebelious' answer, here's what I had to do for Rocket 0.5
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate diesel_migrations;
use capt_server::api::routes;
use diesel_migrations::embed_migrations;
use envy;
use rocket::fairing::AdHoc;
use rocket::{Build, Rocket};
use rocket_sync_db_pools::database;
#[database("sqlite_db")]
pub struct Db(diesel::SqliteConnection);
// This macro from `diesel_migrations` defines an `embedded_migrations` module
// containing a function named `run`. This allows the example to be run and
// tested without any outside setup of the database.
embed_migrations!();
#[launch]
fn rocket() -> _ {
rocket::build()
.attach(Db::fairing())
.attach(AdHoc::try_on_ignite("Database Migrations", migrate))
.mount("/", routes())
}
async fn migrate(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocket<Build>> {
let db = Db::get_one(&rocket).await.expect("database connection");
db.run(|conn| match embedded_migrations::run(&*conn) {
Ok(()) => Ok(rocket),
Err(e) => {
error!("Failed to run database migrations: {:?}", e);
Err(rocket)
}
})
.await
}
Upvotes: 6
Reputation: 1364
Googled some more and found working example here.
Key code
use rocket::Rocket;
use rocket::fairing::AdHoc;
// This macro from `diesel_migrations` defines an `embedded_migrations` module
// containing a function named `run`. This allows the example to be run and
// tested without any outside setup of the database.
embed_migrations!();
#[database("sqlite_database")]
pub struct DbConn(SqliteConnection);
fn run_db_migrations(rocket: Rocket) -> Result<Rocket, Rocket> {
let conn = DbConn::get_one(&rocket).expect("database connection");
match embedded_migrations::run(&*conn) {
Ok(()) => Ok(rocket),
Err(e) => {
error!("Failed to run database migrations: {:?}", e);
Err(rocket)
}
}
}
fn rocket() -> Rocket {
rocket::ignite()
.attach(DbConn::fairing())
.attach(AdHoc::on_attach("Database Migrations", run_db_migrations))
.mount("/", StaticFiles::from("static/"))
.mount("/", routes![index])
.mount("/todo", routes![new, toggle, delete])
.attach(Template::fairing())
}
Upvotes: 11