Has One API
Per-option reference for has_one fields; see the Has One guide for workflows and examples.
Options are passed to the field declaration in app/avo/resources/team.rb:
field :admin, as: :has_one, linkable: trueThese options supplement shared field options. Rails defines the association and any through: relationship, not the field.
Attachment
-> searchable
Replaces the standard attach select with a search-as-you-type picker when the searchable associations add-on is installed and enabled.
field :admin, as: :has_one, searchable: true- Type:
BooleanorHash - Default:
false - Values:
true,false, or a hash withquery:,item:, andenabled:overrides. Other inputs are normalized tofalse. - Context: See Searchable associations and its API for the complete nested contract, callback locals, resource-search fallback, and add-on requirements. Core alone reports this field as not searchable.
-> attach_scope
Defines the records available in the attach picker and accepted when saving an attachment. The initial relation is policy-scoped; returning a fresh relation can widen it beyond that policy scope.
field :admin, as: :has_one, attach_scope: -> { query.where.not(team_id: parent.id) }- Type:
Proc/Lambdareturning an Active Record relation - Default:
nil(the target resource's policy scope) - Context:
Avo::ExecutionContext - Locals:
query(policy-scoped candidate relation),parent(the parent record) - Validation: A submitted ID outside the resulting relation is not accepted as an attachment.
-> attach_fields
Declares extra fields in the attach modal. Values persist on the join record of a has_one :through, including when replacing the current association.
avo >= v4.0.25field :admin, as: :has_one, attach_fields: -> {
field :notes, as: :text
}- Type:
Proc/Lambdacontaining field declarations - Default:
nil - Context:
Avo::FieldsExecutionContext; no attachmentparentorrecordlocals are supplied to the declaration block. Declared fields are hydrated with a new join record. - Validation: Join-record validation failures fail the attach transaction.
WARNING
On a plain has_one, there is no join record on which to persist these values.
Attach and detach callbacks
Sinceavo >= v4.3.11All four callbacks run in Avo::ExecutionContext, with the standard context (including current_user and params) and these explicit locals:
| Local | Value |
|---|---|
parent | The parent record holding the association. |
record | The record being attached or detached. |
resource | The parent resource. |
field | The association field. |
Hooks apply only to Attach and Detach, not Create, nested forms, record deletion, application code, or API writes. An attach reaching an occupied association replaces its current record and runs that record's detach hooks before the new record's corresponding attach hooks. Replacement checks the parent's attach permission, not its detach permission. Attaching the same record again runs attach hooks without detach hooks. A detach naming an unrelated record runs no hooks; for a through association it is a no-op, while a plain has_one raises ActiveRecord::RecordNotFound.
-> before_attach
Runs before the record is attached, inside the attach transaction. Return values are ignored; raising a regular error rolls back the attach and shows its message to the user.
field :admin, as: :has_one, before_attach: -> {
raise "This user is archived" if record.try(:archived?)
}- Type:
Proc/Lambda - Default:
nil - Locals:
parent,record,resource,field, as described above.
-> after_attach
Runs after the attach transaction commits, only on success. An exception does not undo the attachment and reaches the user as an error response.
field :admin, as: :has_one, after_attach: -> {
Rails.logger.info "Attached #{record.id} to #{parent.id}"
}- Type:
Proc/Lambda - Default:
nil - Locals:
parent,record,resource,field, as described above.
-> before_detach
Runs inside the detach transaction, before removal. Raising a regular error rolls back removal. A direct Detach returns an error response; a detach caused by replacement fails the attach and displays the error message.
field :admin, as: :has_one, before_detach: -> {
raise "This user must remain attached" if record.try(:protected?)
}- Type:
Proc/Lambda - Default:
nil - Locals:
parent,record,resource,field, as described above. - Return value: Ignored.
-> after_detach
Runs after the detach transaction commits, only on success. For a plain has_one with dependent: :destroy or :delete, record is already deleted. A through association removes only its join record. Exceptions do not undo removal and prevent later hooks, including a replacement's after_attach, from running.
field :admin, as: :has_one, after_detach: -> {
Rails.logger.info "Detached #{record.id} from #{parent.id}"
}- Type:
Proc/Lambda - Default:
nil - Locals:
parent,record,resource,field, as described above.
WARNING
ActiveRecord::Rollback is swallowed inside before-hook transactions, producing a generic failure rather than the error's message. In after-hooks it cannot roll back the already committed change. Rescue side-effect failures inside after-hooks when they must not reach the user.
Panel presentation
-> description
Text below the association title on a manual-loading placeholder. The loaded Has One header uses the target resource's description, not this field option.
field :admin, as: :has_one, description: "The user responsible for this team."- Type:
Stringor zero-argumentProc/Lambda - Default:
nil - Context:
Avo::ExecutionContext - Locals:
loading_typeis:manualfor the placeholder andnilotherwise. Noquerylocal is supplied by this field.
WARNING
The callable runs when the header renders, even before the user clicks Load. Database work inside it can defeat manual loading.
-> use_resource
Overrides the resource used for the association instead of inferring it from Rails reflection.
field :admin, as: :has_one, use_resource: Avo::Resources::User- Type: Avo resource
Classor fully qualified class-nameString - Default:
nil(inferred resource)
-> linkable
Adds an open-in-new-tab icon to the association panel title, linking to the associated record's Show page.
field :admin, as: :has_one, linkable: true- Type:
Booleanor zero-argumentProc/Lambda - Default:
nil(no icon) - Context:
Avo::ExecutionContext; no field-specific locals are supplied.
-> reloadable
Stores the shared frame reload-control setting. The current Has One Show header does not render this control; the reload icon is implemented on collection association headers.
field :admin, as: :has_one, reloadable: true- Type:
Booleanor zero-argumentProc/Lambda - Default:
nil(no icon) - Context:
Avo::ExecutionContext; no field-specific locals are supplied.
INFO
Setting this option does not currently add a reload icon to a Has One panel.
Frame loading
-> loading
Controls fetching of the associated record's panel. An empty association renders the attach/create state instead of a manual placeholder. Manual deferral applies to display views, not an Edit page's Show panel.
field :admin, as: :has_one, loading: { mode: :manual, auto_load_for: 5.minutes }| Value | Behavior |
|---|---|
:lazy or { mode: :lazy } | Fetches when the frame is revealed. |
:manual or { mode: :manual } | Shows a Load button until opened or remembered. |
{ auto_load_for: 5.minutes } | Hashes without mode select manual mode. |
- Type:
Symbol,String, orHash; strings are converted to symbols, and hash keys are symbolized. - Default:
nilat field level, inheritingconfig.associations[:frames][:loading], which defaults to:lazy. - Values: Supported modes are
:lazyand:manual. - Validation: Modes are not explicitly validated; an unrecognized mode selects neither lazy nor manual behavior.
-> mode
The loading mode in the hash form.
field :admin, as: :has_one, loading: { mode: :manual }- Type:
SymbolorString - Default:
:manualwhen the hash omitsmodeor sets it tonil - Values:
:lazy,:manual
-> auto_load_for
Sliding cookie-based memory window for an opened manual frame, scoped to the record and frame. Return visits within the window refresh it. It is not a fetch delay.
field :admin, as: :has_one, loading: { mode: :manual, auto_load_for: 0 }- Type:
Integerseconds,ActiveSupport::Duration, ornil; converted withto_i. - Default:
config.associations[:frames][:auto_load_for], initially900seconds (15 minutes). - Values: Positive durations enable memory;
0, negative values, or explicitnildisable it. Memory is used only for manual frames.
Nested forms
-> nested
Enables the associated resource's edit fields inside the parent form. Requires avo-nested and the model's accepts_nested_attributes_for; the add-on raises when the model has not configured nested attributes.
field :admin, as: :has_one, nested: true- Type:
BooleanorHash - Default:
{}(disabled) - Values:
trueexpands to{ on: [:new, :edit] };falseornildisables nesting. A hash selects views withon:. - Validation: No general option-schema validation is performed.
limit:is not a Has One option.
-> on
Views in which the nested form is used.
field :admin, as: :has_one, nested: { on: :edit }- Type:
SymbolorArrayof view names - Default:
[:new, :edit]fornested: true; no nesting when a hash omitson. - Values:
:new,:edit,[:new, :edit], or:forms(normalized to both forms). Create and Update requests map to New and Edit respectively.
For model setup, deletion, and nested authorization, see Edit the child in the parent form. To show the non-editable association panel on Edit instead, use shared show_on.