Using persist with actix multiform tempfile

Hello! I'm using the actix multiform module and I've defined this form:

pub struct DbUpload {
    db_file: TempFile,
    last_modify_ts: Text<i64>,
    compression: Text<String>,
    original_hash: Text<String>,
    index: Text<i64>,
    length: Text<i64>,
    nonce: Text<i64>,
}

and later I try to do

let stored_file =  form.db_file.file.persist(new_path);

but the compiler gives me this error

error[E0507]: cannot move out of dereference of `MultipartForm<DbUpload>`
   --> src/routes/backups.rs:98:24
    |
98  |     let stored_file =  form.db_file.file.persist(new_path);
    |                        ^^^^^^^^^^^^^^^^^ ----------------- value moved due to this method call
    |                        |
    |                        move occurs because value has type `NamedTempFile`, which does not implement the `Copy` trait
    |

I checked their examples and it works there because they are using a vec instead of a single file. examples/forms/multipart/src/main.rs at 887d3779f43e67fd7b3ea2af7e12e56f09d83357 · actix/examples · GitHub. Anyone could guide me about how to do it with a single file? Thanks

The error message only makes sense if form comes from a reference, such as if the function signature were this:

async fn save_files(
    &mut MultipartForm(form): &mut MultipartForm<DbUpload>,
) -> Result<impl Responder, Error> {

But I can't say for sure without seeing the whole function.

Thanks! I made a smaller replica of my code since I have authentication logic but tried and this example produces the same error

pub async fn backup_upload(
    form: MultipartForm<DbUpload>,
    request: HttpRequest,
    pool: web::Data<PgPool>,
) -> impl Responder {
    let user_id = "user_id".to_string();

    let new_file_name = format!("{}.db.temp", digest(user_id.clone()));
    let new_path = format!(
        "{}/{}",
        env::var("NEST_DB_DATA_FOLDER").unwrap_or("tmp".to_string()),
        new_file_name,
    );
    
    let stored_file =  form.db_file.file.persist(new_path);
}

I see what happened, now. Try this change:

  pub async fn backup_upload(
-     form: MultipartForm<DbUpload>,
+     MultipartForm(form): MultipartForm<DbUpload>,
      request: HttpRequest,
      pool: web::Data<PgPool>,
  ) -> impl Responder {

The version you have is accessing the member variable through MultipartForm's Deref implementation, which only gives you a reference.

To move out of it, you need to bypass the Deref implementation and, in the example above, destructure it with pattern matching. The into_inner function would work, too.

3 Likes

Thank you very much! It worked. Is always good to learn new things.