Skip to content

Has Many

By default, the HasMany field is visible only on the Show view. You will see a new panel with the model's associated records below the regular fields panel.

ruby
field :projects, as: :has_many

Options

searchable

Turns the attach field/modal from a select input to a searchable experience

ruby
class Avo::Resources::CourseLink < Avo::BaseResource
  def fields
    field :links,
      as: :has_many,
      searchable: true
  end
end

WARNING

Avo uses the search feature behind the scenes, so make sure the target resource has the search_query option configured.

ruby
# app/avo/resources/course_link.rb
class Avo::Resources::CourseLink < Avo::BaseResource
  self.search = {
    query: -> {
      query.ransack(id_eq: params[:q], link_cont: params[:q], m: "or").result(distinct: false)
    }
  }
end

Default

false

Possible values

true, false

attach_scope

Scope out the records the user sees on the Attach modal.

Default

nil

Possible values

ruby
field :user,
  as: :belongs_to,
  attach_scope: -> { query.non_admins }

Pass in a block where you attach scopes to the query object and parent object, which is the actual record where you want to assign the association. The block is executed in the ExecutionContext.

WARNING

The attach_scope will not filter the records in the listing from has_many or has_and_belongs_to_many associations. Use scope or a Pundit policy Scope for that.

ruby
field :members,
  as: :has_many,
  attach_scope: -> { query.where.not(team_id: parent.id) }

In this example, in the attach_scope, we ensure that when attaching members to a team, only those who are not already members will appear in the list of options.

scope

Scope out the records displayed in the table.

Default

nil

Possible values

ruby
field :user,
  as: :belongs_to,
  scope: -> { query.approved }

Pass in a block where you attach scopes to the query object. The block gets executed in the ExecutionContext.

description

Changes the text displayed under the association name.

Default

nil

Possible values

Any string.

use_resource

Sets a different resource to be used when displaying (or redirecting to) the association table.

Default

nil. When nothing is selected, Avo infers the resource type from the reflected association.

Possible values

Avo::Resources::Post, Avo::Resources::PhotoComment, or any Avo resource class.

discreet_pagination

Hides the pagination details when only there's only one page for that association.

Default

false

Possible values

true, false

hide_search_input

Hides the search input displayed on the association table.

Default

false. When nothing is selected and the search_query of association's resource is configured, Avo displays the search input.

Possible values

true, false.

Sets which resource should be used in an STI scenario.

See more on this in the STI section.

Default

false. When it's false it will use the same resource.

Possible values

true, false.

Search query scope

Since v2.13

If the resource used for the has_many association has the search block configured with a query, Avo will use that to scope out the search query to that association.

For example, if you have a Team model that has_many Users, now you'll be able to search through that team's users instead of all of them.

You can target that search using params[:via_association]. When the value of params[:via_association] is has_many, the search has been mad inside a has_many association.

For example, if you want to show the records in a different order, you can do this:

ruby
self.search = {
  query: -> {
    if params[:via_association] == 'has_many'
      query.ransack(id_eq: params[:q], m: "or").result(distinct: false).order(name: :asc)
    else
      query.ransack(id_eq: params[:q], m: "or").result(distinct: false)
    end
  }
}

Has Many Through

The HasMany association also supports the :through option.

ruby
field :members,
  as: :has_many,
  through: :memberships

Show on edit screens

By default, has_and_belongs_to_many is only visible on the Show page. If you want to enable it on the Edit page, too, you need to add the show_on: :edit option.

WARNING

Adding associations on the New screen is not currently supported. The association needs some information from the parent record that hasn't been created yet (because the user is on the New screen).

You may use the redirect helpers to have the following flow:

  1. User is on the New view. They can't see the association panels yet.
  2. User creates the record.
  3. They get redirected to the Show/Edit view, where they can see the association panels.
  4. User attaches associations.

Add scopes to associations

Watch the demo video

When displaying has_many associations, you might want to scope out some associated records. For example, a user might have multiple comments, but on the user's Show page, you don't want to display all the comments, but only the approved ones.

ruby
# app/models/comment.rb
class Comment < ApplicationRecord
  belongs_to :user, optional: true

  scope :approved, -> { where(approved: true) }
end

# app/models/user.rb
class User < ApplicationRecord
  has_many :comments
end

# app/avo/resources/user.rb
class Avo::Resources::User < Avo::BaseResource
  def fields
    field :comments, as: :has_many, scope: -> { query.approved }
  end
end

The comments query on the user Index page will have the approved scope attached.

Association scope

With version 2.5.0, you'll also have access to the parent record so that you can use that to scope your associated models even better.

All the has_many associations have the attach_scope option available too.

Show/hide buttons

You will want to control the visibility of the attach/detach/create/destroy/actions buttons visible throughout your app. You can use the policy methods to do that.

Find out more on the authorization page.

Associations authorization

Reloadable

Since v3.3.6

The reloadable option adds a reload icon next to the association title so users can easily reload just that turbo-frame instead of doing a full page reload.

Usage

To enable the reloadable feature, you have two options:

  1. Direct Boolean Value:

Provide a boolean value directly to the reloadable option. This sets a default behavior where the reloadable feature is either enabled or disabled based on this boolean value.

ruby
field :reviews, as: :has_many, reloadable: true
  1. Dynamic Conditions with a Block:

For more dynamic behavior, you can provide a block to the reloadable option. Within this block, you can specify conditions under which the reloadable should be displayed.

ruby
field :reviews, as: :has_many,
  reloadable: -> {
    current_user.is_admin?
  }

In the above example, the reloadable will be visible if the current_user is an admin.

ExecutionContext

The reloadable block executes within the ExecutionContext, granting access to all default methods and attributes.

Reloadable

association

Since v3.6.2

The for_attribute option allows to specify the association used for a certain field. This option make possible to define same association with different scopes and different name several times on the same resource.

Usage

ruby
field :reviews,
  as: :has_many

field :special_reviews,
  as: :has_many,
  for_attribute: :reviews,
  scope: -> { query.special_reviews }