pub trait RuniqueForm:
Sized
+ Send
+ Sync {
Show 21 methods
// Required methods
fn register_fields(form: &mut Forms);
fn from_form(form: Forms) -> Self;
fn get_form(&self) -> &Forms;
fn get_form_mut(&mut self) -> &mut Forms;
// Provided methods
fn cleaned_string(&self, name: &str) -> Option<String> { ... }
fn cleaned_i32(&self, name: &str) -> Option<i32> { ... }
fn cleaned_i64(&self, name: &str) -> Option<i64> { ... }
fn cleaned_u32(&self, name: &str) -> Option<u32> { ... }
fn cleaned_u64(&self, name: &str) -> Option<u64> { ... }
fn cleaned_f32(&self, name: &str) -> Option<f32> { ... }
fn cleaned_f64(&self, name: &str) -> Option<f64> { ... }
fn cleaned_bool(&self, name: &str) -> Option<bool> { ... }
fn clear(&mut self) { ... }
fn clean_field<'life0, 'life1, 'async_trait>(
&'life0 mut self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn clean<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<(), StrMap>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn is_valid<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn save_txn<'life0, 'life1, 'async_trait>(
&'life0 mut self,
_txn: &'life1 DatabaseTransaction,
) -> Pin<Box<dyn Future<Output = Result<(), DbErr>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn save<'life0, 'life1, 'async_trait>(
&'life0 mut self,
db: &'life1 DatabaseConnection,
) -> Pin<Box<dyn Future<Output = Result<(), DbErr>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn database_error(&mut self, err: &DbErr) { ... }
fn build(tera: ATera, csrf_token: &str) -> Self { ... }
fn build_with_data<'life0, 'life1, 'async_trait>(
raw_data: &'life0 StrMap,
tera: ATera,
csrf_token: &'life1 str,
method: Method,
) -> Pin<Box<dyn Future<Output = Self> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
}Expand description
Main trait for typed forms with validation and saving
§Formulaire basé modèle avec #[form(...)] et impl_form_access!(model)
La macro #[form(...)] génère la struct et impl ModelForm.
Le dev écrit impl RuniqueForm avec impl_form_access!(model) pour brancher les champs du modèle.
use runique::prelude::*;
#[form(schema = user_schema, fields = [username, email, password])]
pub struct RegisterForm;
impl RuniqueForm for RegisterForm {
impl_form_access!(model);
}§Avec validation métier
#[async_trait] requis uniquement quand on override une méthode async :
use runique::prelude::*;
#[form(schema = user_schema, fields = [username, email, password])]
pub struct RegisterForm;
#[async_trait]
impl RuniqueForm for RegisterForm {
impl_form_access!(model);
async fn clean(&mut self) -> Result<(), StrMap> {
let mut errors = StrMap::new();
if self.get_string("username").len() < 3 {
errors.insert("username".to_string(), "Minimum 3 caractères".to_string());
}
if !self.get_string("email").contains('@') {
errors.insert("email".to_string(), "Email invalide".to_string());
}
if errors.is_empty() { Ok(()) } else { Err(errors) }
}
}§Validation métier : clean_field, clean et save
use runique::prelude::*;
use runique::forms::{RuniqueForm, Forms};
use runique::forms::fields::text::TextField;
use sea_orm::{DatabaseTransaction, DbErr, Set};
pub struct ChangePasswordForm {
form: Forms,
}
#[async_trait]
impl RuniqueForm for ChangePasswordForm {
impl_form_access!();
fn register_fields(form: &mut Forms) {
form.field(&TextField::password("password").label("Nouveau mot de passe").required());
form.field(&TextField::password("confirm").label("Confirmation").required());
}
/// Validation par champ — appelée pour chaque champ par is_valid()
async fn clean_field(&mut self, name: &str) -> bool {
match name {
"password" => {
let pwd = self.get_form().get_string("password");
if pwd.len() < 8 {
if let Some(field) = self.get_form_mut().fields.get_mut("password") {
field.set_error("Le mot de passe doit faire au moins 8 caractères".to_string());
}
return false;
}
true
}
_ => true,
}
}
/// Validation globale inter-champs — appelée après tous les clean_field()
async fn clean(&mut self) -> Result<(), StrMap> {
let password = self.get_form().get_string("password");
let confirm = self.get_form().get_string("confirm");
if password != confirm {
let mut errors = StrMap::new();
errors.insert("confirm".to_string(), "Les mots de passe ne correspondent pas".to_string());
return Err(errors);
}
Ok(())
}
/// Sauvegarde dans une transaction — appelée par save()
async fn save_txn(&mut self, _txn: &DatabaseTransaction) -> Result<(), DbErr> {
// let hashed = hash(&self.get_form().get_string("password")).unwrap_or_default();
// UserActiveModel { password: Set(hashed), ..Default::default() }.update(_txn).await?;
Ok(())
}
}Required Methods§
fn register_fields(form: &mut Forms)
fn from_form(form: Forms) -> Self
fn get_form(&self) -> &Forms
fn get_form_mut(&mut self) -> &mut Forms
Provided Methods§
Sourcefn cleaned_string(&self, name: &str) -> Option<String>
fn cleaned_string(&self, name: &str) -> Option<String>
String — None if the field is unknown or empty.
Sourcefn cleaned_i32(&self, name: &str) -> Option<i32>
fn cleaned_i32(&self, name: &str) -> Option<i32>
i32 — None if unknown, empty, or not parseable.
Sourcefn cleaned_i64(&self, name: &str) -> Option<i64>
fn cleaned_i64(&self, name: &str) -> Option<i64>
i64 — None if unknown, empty, or not parseable.
Sourcefn cleaned_u32(&self, name: &str) -> Option<u32>
fn cleaned_u32(&self, name: &str) -> Option<u32>
u32 — None if unknown, empty, or not parseable.
Sourcefn cleaned_u64(&self, name: &str) -> Option<u64>
fn cleaned_u64(&self, name: &str) -> Option<u64>
u64 — None if unknown, empty, or not parseable.
Sourcefn cleaned_f32(&self, name: &str) -> Option<f32>
fn cleaned_f32(&self, name: &str) -> Option<f32>
f32 — handles , → .. None if unknown, empty, or not parseable.
Sourcefn cleaned_f64(&self, name: &str) -> Option<f64>
fn cleaned_f64(&self, name: &str) -> Option<f64>
f64 — handles , → .. None if unknown, empty, or not parseable.
Sourcefn cleaned_bool(&self, name: &str) -> Option<bool>
fn cleaned_bool(&self, name: &str) -> Option<bool>
bool — true for "true", "1", "on" (case-insensitive).
Returns None if the field does not exist in the form.
Note: fill() normalizes unchecked checkboxes/radios to "false",
so this method always returns Some(_) for a submitted boolean field.
fn clean_field<'life0, 'life1, 'async_trait>(
&'life0 mut self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn clean<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<(), StrMap>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn is_valid<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Sourcefn save_txn<'life0, 'life1, 'async_trait>(
&'life0 mut self,
_txn: &'life1 DatabaseTransaction,
) -> Pin<Box<dyn Future<Output = Result<(), DbErr>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn save_txn<'life0, 'life1, 'async_trait>(
&'life0 mut self,
_txn: &'life1 DatabaseTransaction,
) -> Pin<Box<dyn Future<Output = Result<(), DbErr>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Default atomic wrapper: opens a transaction and calls save_txn.
- if
save_txnreturns Err -> automatic rollback - otherwise -> commit
Sourcefn save<'life0, 'life1, 'async_trait>(
&'life0 mut self,
db: &'life1 DatabaseConnection,
) -> Pin<Box<dyn Future<Output = Result<(), DbErr>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn save<'life0, 'life1, 'async_trait>(
&'life0 mut self,
db: &'life1 DatabaseConnection,
) -> Pin<Box<dyn Future<Output = Result<(), DbErr>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Atomic wrapper: explicit transaction (avoids the ’static futures trap)
fn database_error(&mut self, err: &DbErr)
fn build(tera: ATera, csrf_token: &str) -> Self
fn build_with_data<'life0, 'life1, 'async_trait>(
raw_data: &'life0 StrMap,
tera: ATera,
csrf_token: &'life1 str,
method: Method,
) -> Pin<Box<dyn Future<Output = Self> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.