Field::HasMany
The HasMany association field wraps a has_many association on your model. By default it adds a list of associated records to the show page and on edit and new pages it renders a searchable dropdown field with checkboxes to select multiple options.

How to add a HasMany field
To add the basic HasMany field to a repository, return it as part of the #fields method:
def fields
[
Field::HasMany.new(:projects)
]
end
HasMany fields use the same searchable options as the associated repository. This also means that if the repository has no searchable fields, the filter input doesn’t work.
Search
Not searchable by default. The field isn’t backed by a real column, so enabling it needs a searchable lambda - see Search for columns in an associated table.
#collection_query
The chainable #collection_query method lets you control what records are included in the dropdown. It accepts a proc, which is called when the user opens the dropdown or changes the filter input. The proc receives an ActiveRecord::Relation with all records matching the filter query.
Field::HasMany.new(:projects)
.collection_query(->(query:) {
query.some_scope
})
The proc can accept the following keyword arguments:
context: TheUchi::Contextwe’re currently processing.query: TheActiveRecord::Relationdescribed above.
How to limit what records are returned
You can use #collection_query to limit what records are returned. The currently logged-in user is available as context.user, see Current user.
For example, if your User model has a projects method that returns the Project records the current user is allowed to access, you could do something like:
Field::HasMany.new(:projects)
.collection_query(->(context:, query:) {
query.where(id: context.user.projects)
})
How to control the order of records in dropdowns
When opening the record selector of a HasMany field the records are returned in the default order defined by the repository. To do something else, pass a proc to the #collection_query method:
Field::HasMany.new(:projects)
.collection_query(->(query:) {
query.reorder(budget: :desc)
})
The proc receives an ActiveRecord::Relation with all records returned from the repository. Note that you might have to use #reorder, not just #order, since the relation may already have an order defined.
How to change titles in the dropdown
The dropdown displays the title of the record. For example, a Person repository may use the name attribute as its title. To customize the title for a record, implement Repository#title, see repositories documentation for details.
#nested_fields
By default, a HasMany field lets users pick from existing associated records. The chainable #nested_fields method switches it into an inline editor instead: it creates, edits, and deletes associated records directly within the parent form.
Your model must use accepts_nested_attributes_for for this to work:
class Book < ApplicationRecord
has_many :titles
accepts_nested_attributes_for :titles, allow_destroy: true
end
Configure #nested_fields with the fields you want to edit for each associated record:
module Uchi
module Repositories
class Book < Repository
def fields
[
Field::String.new(:original_title),
Field::HasMany.new(:titles).nested_fields(
Field::String.new(:title),
Field::String.new(:locale)
)
]
end
end
end
end
This also accepts an array:
Field::HasMany.new(:titles).nested_fields([
Field::String.new(:title),
Field::String.new(:locale)
])
Once #nested_fields is configured, the field switches its rendering on both the edit and the show pages: the show page lists each associated record’s configured fields inline instead of loading a scoped index view in a turbo-frame, and the edit/new pages render an inline editor instead of the searchable dropdown. #collection_query has no effect when #nested_fields is configured.
Supported nested field types
String- single-line textText- multi-line textNumber- integers, decimalsBoolean- checkboxesDate- date pickerDateTime- datetime picker
Advanced model options
Reject blank records to avoid creating empty associated records:
class Book < ApplicationRecord
accepts_nested_attributes_for :titles,
allow_destroy: true,
reject_if: :all_blank
end
Limit nested records to prevent abuse:
accepts_nested_attributes_for :titles,
allow_destroy: true,
limit: 10
Read more in Rails’ NestedAttributes documentation.