Ruby Developer Guide
Other documentationsDemoCommunityGitHub
  • Forest Admin
  • Getting started
    • How it works
    • Quick start
      • Ruby on Rails
    • Create your agent
    • Troubleshooting
    • Migrating legacy agents
      • Pre-requisites
      • Recommendations
      • Migration steps
      • Code transformations
        • API Charts
        • Live Queries
        • Smart Charts
        • Route overrides
        • Smart Actions
        • Smart Fields
        • Smart Relationships
        • Smart Segments
  • Data Sources
    • Getting Started
      • Collection selection
      • Naming conflicts
      • Query interface and Native Queries
        • Fields and projections
        • Filters
        • Aggregations
    • Provided data sources
      • ActiveRecord
        • Polymorphic relationships
      • Mongoid
    • Write your own
      • Translation strategy
        • Structure declaration
        • Capabilities declaration
        • Read implementation
        • Write implementation
        • Intra-data source Relationships
      • Contribute
  • Agent customization
    • Getting Started
    • Actions
      • Scope and context
      • Result builder
      • Static Forms
      • Widgets in Forms
      • Dynamic Forms
      • Form layout customization
      • Related data invalidation
    • Charts
      • Value
      • Objective
      • Percentage
      • Distribution
      • Leaderboard
      • Time-based
    • Fields
      • Add fields
      • Move, rename and remove fields
      • Override binary field mode
      • Override writing behavior
      • Override filtering behavior
      • Override sorting behavior
      • Validation
    • Hooks
      • Collection hook
      • Collection override
    • Pagination
    • Plugins
      • Write your own
    • Relationships
      • To a single record
      • To multiple records
      • Computed foreign keys
      • Under the hood
    • Search
    • Segments
  • Frontend customization
    • Smart Charts
      • Create a table chart
      • Create a bar chart
      • Create a cohort chart
      • Create a density map
    • Smart Views
      • Create a Map view
      • Create a Calendar view
      • Create a Shipping view
      • Create a Gallery view
      • Create a custom tinder-like validation view
      • Create a custom moderation view
  • Deploying to production
    • Environments
      • Deploy on AWS
      • Deploy on Heroku
      • Deploy on GCP
      • Deploy on Ubuntu
    • Development workflow
    • Using branches
    • Deploying your changes
    • Forest Admin CLI commands
      • init
      • login
      • branch
      • switch
      • set-origin
      • push
      • environments:create
      • environments:reset
      • deploy
  • Under the hood
    • .forestadmin-schema.json
    • Data Model
      • Typing
      • Relationships
    • Security & Privacy
Powered by GitBook
On this page
  • One-to-Many relations
  • Many-to-Many relations
  • External relations

Was this helpful?

  1. Agent customization
  2. Relationships

To multiple records

PreviousTo a single recordNextComputed foreign keys

Last updated 12 months ago

Was this helpful?

This is the official documentation of the agent_ruby Ruby agent.

Relationships that point to multiple records are displayed in the frontend in the "Related Data" and "Explorer" Tab.

One-to-Many relations

In a one-to-many relationship, one record from a Collection is attached to multiple records of another Collection.

Think about countries and towns: a country has multiple towns, and each town belongs to a country.

@create_agent.customize_collection('country') do |collection|
  collection.add_one_to_many_relation(
    'myTown',
    'town',
    {
      origin_key: 'country_id',
      origin_key_target: 'id' # Optional (uses primary key of countries by default)
    }
  )
end

Many-to-Many relations

In a many-to-many relation, 3 Collections are used instead of 2 to build the relation.

This allows multiple records from one Collection to be attached to multiple records from another Collection.

For instance, on a movie recommendation website, each user can rate many movies, and each movie can be rated by many users. The 3 Collections that are used are users (the "origin" Collection), ratings (the "through" Collection), and movies (the "foreign" Collection).

@create_agent.customize_collection('user') do |collection|
  collection.add_many_to_many_relation(
    'ratedMovies',
    'movie',
    'rating',
    {
      origin_key: 'user_id',
      foreign_key: 'movie_id',
    }
  )

  # ... and the other one.
  collection.customize_collection('Movie') do |collection|
      # ⚠️ Not 'OneToOne'
    collection.add_many_to_one_relation(
      'whoRatedThisMovie',
      'user',
      'rating',
      {
        origin_key_target: 'id', # Optional (uses primary key of Movie by default)
        origin_key: 'movie_id',
        foreign_key: 'user_id',
        foreign_key_target: 'id', # Optional (uses primary key of User by default)
      }
    )
  end
end

External relations

External relations allow to define Collections which will only be available through the "Related Data" section or a given model.

Note that external relations do not support pagination.

@create_agent.customize_collection('address') do |collection|
  states = [
    { 'code' => 'AK', 'name' => 'Alaska', 'zip' => [99501, 99950], 'closeTo' => [] },
    { 'code' => 'AL', 'name' => 'Alabama', 'zip' => [35004, 36925], 'closeTo' => ['TE', 'MI', 'GE'] },
    { 'code' => 'AR', 'name' => 'Arkansas', 'zip' => [71601, 72959], 'closeTo' => ['OK', 'TX', 'LO'] },
    { 'code' => 'AZ', 'name' => 'Arizona', 'zip' => [85001, 86556], 'closeTo' => ['NM', 'CO', 'NE'] },
    { 'code' => 'CA', 'name' => 'California', 'zip' => [90001, 96162], 'closeTo' => ['OR', 'NE'] },
  # ....
  ]

  collection.add_external_relation(
    'nearStates',
    {
      # Define schema of the records in the relation.
      schema: { 'code' => 'Number', 'name' => 'String' },

      # Which fields are needed from the parent record to run the handler?
      # Dependencies are optional: by default only the primary key of address would be provided.
      dependencies: %w[country zipCode],

      # Compute list of records from the parent record
      list_records: proc { |record|
        if record['country'] == 'USA'
          state = states.find { |s| s['zip'][0] < record['zipCode'] && record['zipCode'] < s['zip'][1] }
          return states.filter { |s| state['closeTo'].include?(s['code']) }
        end

        return []
      }
    }
  )
end
Explorer Tab