Skip to content
On this page

Has And Belongs To Many ​

The HasAndBelongsToMany association works similarly to HasMany.

ruby
field :users, as: :has_and_belongs_to_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. The block is executed in the ExecutionContext.

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.

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
  }
}

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.

Searchable has_and_belongs_to_many ​

Similar to belongs_to, the has_many associations support the searchable option.

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