I am still working on my API and I did run into the issue where I wanted my handlers do just one thing
use actix::prelude::*;
use actix_web::*;
use diesel;
use diesel::prelude::*;
use validator::{Validate};
use schema;
use user;
use user::models;
use db::DbExecutor;
use user::models::NewUser;
use user::dbhandler::register::CreateRegistrationLink;
use uuid::Uuid;
#[derive(Deserialize, Validate)]
pub struct CreateUser {
#[validate(email)]
pub email: String,
#[validate(length(min = "8"))]
pub password: String,
}
impl Message for CreateUser {
type Result = Result<user::models::User, Error>;
}
impl Handler<CreateUser> for DbExecutor {
type Result = Result<user::models::User, Error>;
fn handle(&mut self, msg: CreateUser, ctx: &mut Self::Context) -> Self::Result {
use self::schema::users::dsl::*;
let new_user = NewUser {
email: &msg.email,
password: &msg.password
};
let conn: &PgConnection = &self.0.get().unwrap();
diesel::insert_into(users)
.values(&new_user)
.execute(conn)
.map_err(|_| error::ErrorInternalServerError("Error inserting person"))?;
let mut items = users
.filter(email.eq(&msg.email))
.load::<models::User>(conn)
.map_err(|_| error::ErrorInternalServerError("Error loading person"))?;
let user = items.pop().unwrap();
// this is the idea what I want to achieve
let new_registration_link = CreateRegistrationLink{
user_id: user.id,
uuid: Uuid::new_v4().to_string(),
};
self.send(ctx);
// till here
Ok(user)
}
}
which will be called by
fn create_user(
(state, params): (State<AppState>, Form<CreateUser>),
) -> FutureResponse<HttpResponse> {
let email = params.email.clone();
let password = params.password.clone();
let create_user = CreateUser {
email,
password
};
match create_user.validate() {
Ok(_) => {
state
.db
.send(create_user)
.from_err()
.and_then(|res| {
match res {
Ok(user) => Ok(HttpResponse::Ok().json(
AppResponse::success(user, "Success".to_string())
)),
Err(_) => Ok(HttpResponse::InternalServerError().into()),
}
})
.responder()
},
Err(e) => Box::new(ok::<HttpResponse, Error>(HttpResponse::BadRequest().json(
AppResponse::fail(e, "Error during creation".to_string())
)))
}
}
which uses my actor:
use actix::prelude::*;
use diesel::prelude::*;
use diesel::r2d2::{ConnectionManager, Pool};
pub struct DbExecutor(pub Pool<ConnectionManager<PgConnection>>);
impl Actor for DbExecutor {
type Context = SyncContext<Self>;
}
besides my tendency to clone things out of lazyness ;)
I don't want my database handler for user creation to create the message to the actor (itself) which then pass the new creation message to create the verification link.
I read some solution where I would have to spawn a new arbiter but this seams overkill. the other approach would be to do it in the handler.
To my question :) does anyone actually know how to access the actor to dispatch a message to itself? I probably just miss something obvious like a response channel implementation my actor does need. But all direct channel implementations are private and maybe one here already faced a similar issue.
Also I am not sure if this is the best approach so this is more because I am curious and I will most likely solve it with the future in the api endpoint just to avoid complexity between handlers.
Still ... I am curious :)
No responses yet.