Skip to main content

Relation

Struct Relation 

Source
pub struct Relation<P> { /* private fields */ }
Expand description

One relation of a parent resource’s records.

Declared by ResourceDef::relation; the related resource must be registered on the same panel, which keys the relation by its slug:

let def: ResourceDef<PostResource> =
    ResourceDef::new().relation(Relation::has_many::<CommentResource>(Comment::fields().post_id()));

The table is the related resource’s own list table, its columns, search, sort, filters and pager, over its tenant-scoped query narrowed to the record, titled with its plural label or label:

  • its policy applies as on its own list: no section renders when it refuses ViewAny, or when the resource is tenant-scoped and the request has no tenant, and each row keeps only the actions its record allows;
  • a has_many table carries the related resource’s View, Edit, Delete and custom actions and its bulk bar, and a create button when the related resource has a form and its policy allows Create. The button opens the create page with the owner preselected, as in /admin/comments/-/create?post_id=…: a default for a relationship choice only, validated like any other create;
  • a belongs_to_many table keeps View, Edit and Delete, and offers no custom action and no create button, since a record created there would link nothing;
  • writes started from the table carry ?return= and land back on the page, which the panel follows only to a path under its own prefix;
  • its URL parameters take the related resource’s slug as a prefix, as in ?comments.q=, so several tables share one page, and sorting, searching, filtering and paging update it in place. On the edit page that keeps the fields the user edited, but loses repeater rows added and options fetched since the page loaded. A refused save renders no related table.

Mounting refuses a relation to a resource the panel does not register, and two relations of one resource to the same related resource.

Implementations§

Source§

impl<P> Relation<P>
where P: Model + IntoExpr<P> + 'static,

Source

pub fn has_many<C>( foreign_key: Path<C::Model, impl ForeignKey<P::PrimaryKey>>, ) -> Self
where C: Resource,

Declare a has_many child resource whose foreign_key holds the owner’s primary key, a single column.

let comments: Relation<Post> = Relation::has_many::<CommentResource>(Comment::fields().post_id());
Source

pub fn belongs_to_many<C>(via: impl Into<Path<P, List<C::Model>>>) -> Self
where C: Resource, P: Send + Sync,

Declare a many-to-many child resource whose records the owner links through via, its #[has_many(via = joins.target)] field: the owner’s linked records, which the table attaches and detaches as join rows.

let tags: Relation<Post> = Relation::belongs_to_many::<TagResource>(Post::fields().tags());

The section’s header carries Attach, whose dialog asks for one record through a searchable choice offered as a relationship’s options are; attaching a linked record changes nothing. Each row and the bulk bar carry Detach, which deletes the join rows and leaves the records. Both post under the owner’s record: {list}/{key}/-/relations/{slug}/-/actions/attach, …/-/actions/detach with the selection’s ids, and …/{related}/-/actions/detach for one row. The owner’s hooks receive Change::Attach or Change::Detach.

Attaching and detaching ask the owner’s policy for Update, as editing it does: no button renders without it, and the routes answer 403. A record the related resource’s policy refuses View is neither offered nor detached. Mounting refuses a join model a link cannot write.

Source§

impl<P> Relation<P>

Source

pub fn label(self, label: impl Into<Text>) -> Self

Titles the section label instead of the related resource’s plural label.

Trait Implementations§

Source§

impl<P> Debug for Relation<P>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<P> !RefUnwindSafe for Relation<P>

§

impl<P> !UnwindSafe for Relation<P>

§

impl<P> Freeze for Relation<P>
where RelationKind<P>: Freeze, Arc<dyn Fn(&P) -> (Expr<bool>, String) + Send + Sync>: Freeze,

§

impl<P> Send for Relation<P>
where RelationKind<P>: Send, Arc<dyn Fn(&P) -> (Expr<bool>, String) + Send + Sync>: Send,

§

impl<P> Sync for Relation<P>
where RelationKind<P>: Sync, Arc<dyn Fn(&P) -> (Expr<bool>, String) + Send + Sync>: Sync,

§

impl<P> Unpin for Relation<P>
where RelationKind<P>: Unpin, Arc<dyn Fn(&P) -> (Expr<bool>, String) + Send + Sync>: Unpin,

§

impl<P> UnsafeUnpin for Relation<P>
where RelationKind<P>: UnsafeUnpin, Arc<dyn Fn(&P) -> (Expr<bool>, String) + Send + Sync>: UnsafeUnpin,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more