pub struct NestedChangeset<P, C> {
pub parent: Changeset<P>,
/* private fields */
}Expand description
A parent Changeset<P> plus its bound child collection.
Obtain one from decode_nested_urlencoded or (preferred) the
NestedChangesetForm axum extractor.
Fields§
§parent: Changeset<P>The parent changeset (values + per-field errors), reusing the existing
Changeset pipeline.
Implementations§
Source§impl<P, C: NestedChild> NestedChangeset<P, C>
impl<P, C: NestedChild> NestedChangeset<P, C>
Sourcepub fn blank(parent: P) -> Self
pub fn blank(parent: P) -> Self
Build a blank, non-validating nested changeset for the initial
new (create) render, before the user has submitted anything.
Mirrors ChangesetForm::blank: it
wraps parent in a valid Changeset (via Changeset::new, which
records no errors — it does not run validator::Validate)
with zero child rows. So is_valid() returns true,
errors_for(..) is empty, rows() is empty, and into_valid() returns
Ok((parent, vec![])) even when a required parent field is still empty.
Use this for the initial GET render of an empty (create) form so the
blank page does not show a premature “field is required” error or
aria-invalid="true" before the user has typed. For an edit render
that must display existing child rows (with their persisted ids), use
seeded instead — blank produces zero child
rows and cannot pre-fill or preserve existing line items. Use
decode_nested_urlencoded (or the NestedChangesetForm extractor)
for the POST decode that validates a real submission and re-renders with
inline errors.
Sourcepub fn is_valid(&self) -> bool
pub fn is_valid(&self) -> bool
true when the parent is valid, every non-destroyed row has no
errors, and the children all parsed and validated.
Sourcepub fn into_valid(self) -> Result<(P, Vec<C>), Self>
pub fn into_valid(self) -> Result<(P, Vec<C>), Self>
Consume the changeset, returning Ok((parent, children)) when valid or
Err(self) (with all rows retained for re-render) when not.
The returned child vector contains only non-destroyed rows, in order.
§Errors
Returns Err(self) when the parent or any non-destroyed child row has
validation errors, or any child failed to parse.
Sourcepub fn errors_for(&self, key: &str) -> &[String]
pub fn errors_for(&self, key: &str) -> &[String]
Validation messages for key, or an empty slice.
Supports both parent field keys (delegated to
Changeset::errors_for) and combined child keys of the form
"{COLLECTION}[{i}].{sub}" (e.g. "items[1].quantity"). A bare
"{COLLECTION}[{i}]" returns that row’s row-level (parse) errors.
Sourcepub fn rows(&self) -> &[NestedRow]
pub fn rows(&self) -> &[NestedRow]
The submitted child rows in compacted (ascending-index) order.
Sourcepub const fn collection_name(&self) -> &'static str
pub const fn collection_name(&self) -> &'static str
The child collection name, i.e. NestedChild::COLLECTION.
Source§impl<P, C: NestedChild + Serialize> NestedChangeset<P, C>
Edit-render seeding — pre-populate a non-validating changeset with existing
persisted children.
impl<P, C: NestedChild + Serialize> NestedChangeset<P, C>
Edit-render seeding — pre-populate a non-validating changeset with existing persisted children.
The extra serde::Serialize bound lives on this impl block alone, so the
core NestedChild trait stays serialize-free; only callers that seed an
edit form need their child type to be serializable.
Sourcepub fn seeded(parent: P, children: Vec<C>) -> Self
pub fn seeded(parent: P, children: Vec<C>) -> Self
Build a non-validating, valid nested changeset that pre-renders one
row per existing child, for the initial edit render of a form that
already has persisted children.
Where blank produces zero child rows (for
the create/new page), seeded produces exactly one NestedRow per
element of children, so an edit form can display and preserve existing
line items — including each child’s id as a hidden input (via
RowScope::hidden_input) — before the first submit. That hidden id
also makes the in-scope _destroy-on-existing-children flow usable: the
row round-trips its identity so ticking Remove on a persisted child
submits a real, identifiable row for the handler to delete.
Each row’s raw values are produced by serializing the child with
serde_urlencoded::to_string and parsing the result back into the
per-subfield map — the same string representation
decode_nested_urlencoded populates from a real submission, so
RowScope::value pre-fills a seeded row’s inputs identically to a
re-rendered submitted row.
Like blank, this does not run validator::Validate: it wraps
parent in a valid Changeset (via Changeset::new) and keeps
valid_children = Some(children), so is_valid() returns true,
errors_for(..) is empty, every seeded row reports no errors and is not
destroyed, and into_valid() returns Ok((parent, children)). Use the
POST decode path (decode_nested_urlencoded / the
NestedChangesetForm extractor) to validate the actual edit
submission.
Deeper reconciliation of persisted children — reordering, or deep-diffing
submitted rows against the seeded set to compute per-row inserts /
updates / deletes — is intentionally out of scope here (see issue
#1346’s out-of-scope list) and remains a follow-up; seeded only
pre-renders the existing rows so the no-JS edit + _destroy flow works.
Trait Implementations§
Auto Trait Implementations§
impl<P, C> Freeze for NestedChangeset<P, C>where
P: Freeze,
impl<P, C> RefUnwindSafe for NestedChangeset<P, C>where
P: RefUnwindSafe,
C: RefUnwindSafe,
impl<P, C> Send for NestedChangeset<P, C>
impl<P, C> Sync for NestedChangeset<P, C>
impl<P, C> Unpin for NestedChangeset<P, C>
impl<P, C> UnsafeUnpin for NestedChangeset<P, C>where
P: UnsafeUnpin,
impl<P, C> UnwindSafe for NestedChangeset<P, C>where
P: UnwindSafe,
C: UnwindSafe,
Blanket Implementations§
Source§impl<T> AggregateExpressionMethods for T
impl<T> AggregateExpressionMethods for T
Source§fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
DISTINCT modifier for aggregate functions Read moreSource§fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
ALL modifier for aggregate functions Read moreSource§fn aggregate_filter<P>(self, f: P) -> Self::Output
fn aggregate_filter<P>(self, f: P) -> Self::Output
Source§fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
Source§impl<T> AutumnDependents for Twhere
T: ?Sized,
impl<T> AutumnDependents for Twhere
T: ?Sized,
Source§fn dependents() -> &'static [RuntimeDependentSpec]
fn dependents() -> &'static [RuntimeDependentSpec]
#[model] overrides via an inherent shadow when dependents exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoSql for T
impl<T> IntoSql for T
Source§fn into_sql<T>(self) -> Self::Expression
fn into_sql<T>(self) -> Self::Expression
self to an expression for Diesel’s query builder. Read moreSource§fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
&self to an expression for Diesel’s query builder. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T, Conn> RunQueryDsl<Conn> for T
impl<T, Conn> RunQueryDsl<Conn> for T
Source§fn execute<'conn, 'query>(
self,
conn: &'conn mut Conn,
) -> <Conn as AsyncConnectionCore>::ExecuteFuture<'conn, 'query>
fn execute<'conn, 'query>( self, conn: &'conn mut Conn, ) -> <Conn as AsyncConnectionCore>::ExecuteFuture<'conn, 'query>
Source§fn load<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
fn load<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
Source§fn load_stream<'conn, 'query, U>(
self,
conn: &'conn mut Conn,
) -> Self::LoadFuture<'conn>where
Conn: AsyncConnectionCore,
U: 'conn,
Self: LoadQuery<'query, Conn, U> + 'query,
fn load_stream<'conn, 'query, U>(
self,
conn: &'conn mut Conn,
) -> Self::LoadFuture<'conn>where
Conn: AsyncConnectionCore,
U: 'conn,
Self: LoadQuery<'query, Conn, U> + 'query,
Stream] with the returned rows. Read moreSource§fn get_result<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, LoadNext<Pin<Box<Self::Stream<'conn>>>>>
fn get_result<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<Self::LoadFuture<'conn>, LoadNext<Pin<Box<Self::Stream<'conn>>>>>
Source§fn get_results<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
fn get_results<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
Vec with the affected rows. Read moreSource§impl<T> Scoped for T
impl<T> Scoped for T
Source§fn scope(ctx: &PolicyContext) -> ScopeQuery<'_, Self>
fn scope(ctx: &PolicyContext) -> ScopeQuery<'_, Self>
ScopeQuery for this type. Resolves the
registered scope at .load() time, not here.