ActiveScaffold show relational value

297 Views Asked by At

I have a simple table being shown in ActiveScaffold. The table has three fields: an ID, a description, and a second ID which is a foreign key to another table. In the ActiveScaffold list view, I want to show the 'name' field from the related table rather than the foreign key value (an unhelpful ID number).

I have looked over the ActiveScaffold basic documentation, FAQ, and forum (as well as doing an SO search) with no luck. The AS API docs describe a boatload of functionality associated with ActiveRecord associations, but appear to have nothing on the basics of setting up these relationships.

How can I accomplish this?

1

There are 1 best solutions below

0
AudioBubble On BEST ANSWER

After two days of searching and experimentation, I ended up figuring this out. Thought I'd post it just in case this is helpful to others.

I'll be using a Customer and Order example below (i.e. a Customer can have multiple Orders, and we want the Customer's name to show in the Order's ActiveScaffold view). The data structure is deliberately kept very simple.

First a couple of basic definitions for the below:

  • The child table is the table that has the foreign key in it. In the example, Orders will have the foreign key from the Person table.
  • The parent table is the table being related to by the child. The Customer table is the parent in the example below.

There are four basic steps to this process:

  1. Set up the relationship in the database.
  2. Set up the relationship in Rails.
  3. Configure ActiveScaffold so it knows what you want to do.
  4. Add a property to the child model that returns the data you want to display.

Here's a walkthrough:

  1. Verify you’ve got a straightforward ActiveScaffold view working for the child. That process is outside the scope of this answer, but see the AS wiki for some straightforward instructions.

  2. Add a foreign key in the child table. In Rails Migration-speak, this requires the creation of the tables, with the foreign ID field in the child table, and then “add_foreign_key [child table symbol], [parent table symbol]” In my case here’s the full migration:

    class CustomerOrderAdd < ActiveRecord::Migration
      def change
        create_table(:customers, primary: :target_group_id) do |t|
          t.column :full_name, :string, null: false
        end
    
        create_table(:orders, primary: :order_id) do |t|
          t.column :customer_id, :int, null: false
          t.column :order_desc, :string, null: false
        end
    
        add_foreign_key :orders, :customers
      end
    end
    
  3. In the parent class, add has_many *child object symbol plural form* In our example, this would be:

    class Customer < ActiveRecord::Base
      has_many :orders
    end
    
  4. In the child class, add belongs_to *parent object symbol singular form* Again in our example, this leads to:

    class Order < ActiveRecord::Base
      belongs_to :target_group
      . . .
    end
    
  5. In the child controller’s ActiveScaffold config block, add a column to your ActiveScaffold columns array that will display the related data from the parent class/table. Name this whatever you’d like to name it. Keep in mind you’ll need to use this in the remaining steps. In our example, this leads to the addition of :customer_name in the columns array:

    class OrdersController < ApplicationController
      active_scaffold :order do |config|
        config.label = 'Customer Orders'
        config.list.sorting = [{customer_id: :asc}]
        config.list.per_page = 30
    
        config.columns = [:id, :order_desc, :customer_name]
    
      end
    end
    
  6. To speed things up a bit, tell ActiveScaffold to load parent table data as soon as possible. In our example, this leads to the following addition to the child controller's ActiveScaffold config area:

    config.columns[:customer_name].includes = :customer]
    
  7. Add a function in your child model named exactly the same as the new column name you added to the ActiveScaffold columns array. In this function, type out the related class/table name with a dot at the end, then the property/column name you want to actually show. In the example, this looks like:

    def customer_name
      customer.full_name
    end
    
  8. Hit your ActiveScaffold index view for the child class/table. Your value should now be in place.