View Source ExTeal.Fields.ManyToMany (ExTeal v0.28.1)
The ManyToMany field corresponds to a many_to_many ecto relationship. For example,
let's assume a User schema has a many_to_many relationship with a Role schema.
We can add the relationship to our User resource like so:
alias ExTeal.Fields.ManyToMany
ManyToMany.make(:roles)Customizing Index Tables
Let's assume we have a User schema with a many_to_many relationship with a Role schema. The pivot
schema has a :primary boolean field. We want to display the Role's name and the User's email and
the primary boolean field on the index table of 'Roles' for a 'User'. We can do this by defining:
ManyToMany.make(:roles, Role)
|> ManyToMany.with_pivot_fields([ExTeal.Fields.Boolean.make(:primary)])The relationship table, attach and edit-attached interfaces now all a user to manage the 'primary' field which only exists on the pivot table.
Customizing Index Tables
By default, the ManyToMany field produces a ManyToManyBelongsTo field on the index table. This field
appears as a BelongsTo field, providing the title for the linked resource and a link to the detail page
of the linked asset, in the previous example 'Role'. There are times where you might need to customize
the index table, overriding the ManyToManyBelongsTo and providing a unique list of fields to display.
Enter with_index_fields/2 and with_index_query/2. By default, Teal queries for both the related resource
and the join to the current resource via some of the meta data associated with the underlying Ecto.Assoc
struct. The results are then loaded in a custom resource lookup select query. When extending the default
many-to-many functionality, the query must return a ExTeal.Resource.pivot_resource() type.
Example
Assume a User has many to many with Org through a Membership schema. Membership has a role field and we want to display some
extra information in the Org many-to-many table for a user. We could define that as:
ManyToMany.make(:orgs, Org)
|> ManyToMany.with_index_fields([
ExTeal.Fields.Text.make(:name)
ExTeal.Fields.Boolean.make(:active),
ExTeal.Fields.Select.make(:org_type),
ExTeal.Fields.Number.make(:member_count) |> ExTeal.Field.virtual()
])
|> ManyToMany.with_index_query(fn query, _assoc, _resource_id ->
query
|> Ecto.Query.join(:left, [o], m in assoc(o, :memberships))
|> Ecto.Query.select(query, [o, x, m], %{
_row: %{
name: o.name,
active: o.active,
org_type: o.org_type,
member_count: selected_as(count(m.id), :member_count)
},
_pivot: x,
pivot: true
})
|> Ecto.Query.group_by([o, x], [o.id, x.org_id])
end)
|> ManyToMany.with_pivot_fields([ExTeal.Fields.Select.make(:role)])What a query, what a pipe. There are some conditions here. This functionality is only available when
a many_to_many assocation is defined with a join_through schema. If the many to many is joined
only through the table name, you may be able to customize the index fields by defining a with_index_fields/2
and ignoring the with_index_query/2 function. If you need to customize the query, you can do so by
simply returning a full schema and avoiding the ExTeal.Resource.pivot_resource() type.
Summary
Functions
Callback implementation for ExTeal.Field.apply_options_for/4.
Callback implementation for ExTeal.Field.default_sortable/0.
Callback implementation for ExTeal.Field.filterable_as/0.
Callback implementation for ExTeal.Field.make/2.
Callback implementation for ExTeal.Field.sanitize_as/0.
Callback implementation for ExTeal.Field.value_for/3.
Functions
Callback implementation for ExTeal.Field.apply_options_for/4.
Callback implementation for ExTeal.Field.default_sortable/0.
Callback implementation for ExTeal.Field.filterable_as/0.
Callback implementation for ExTeal.Field.make/2.
Callback implementation for ExTeal.Field.sanitize_as/0.
Callback implementation for ExTeal.Field.value_for/3.
@spec with_index_fields(ExTeal.Field.t(), [ExTeal.Field.t()]) :: ExTeal.Field.t()
@spec with_index_query(ExTeal.Field.t(), (Ecto.Query.t(), struct(), any() -> Ecto.Query.t())) :: ExTeal.Field.t()