/ Tags: RAILS-CODE / Categories: SOLUTIONS

Add A Custom Computed Column To An Activeadmin Index Page

The default ActiveAdmin index lists raw columns. Real admin screens need derived values — a total from associated rows, a status badge, a link to a related record — and the column block gives you that.

Description

Inside index do ... end, column :name renders an attribute and column("Label") { |record| ... } renders whatever the block returns. The block runs in the view context, so link helpers, number_to_currency, and status_tag all work. The trap is N+1 queries. Every block that touches an association fires a query per row, and an admin index showing thirty rows becomes thirty-one queries. Set includes on the controller scope to fix it. A computed column is not sortable by default, since there is no column for SQL to order by. Pass sortable: :some_column when a real column can stand in for it.

Sample input:

  column("Total") { |order| number_to_currency(order.total_cents / 100.0) }


Sample Output:

  | ID | Customer   | Items | Total   | Status    |
  | 42 | Acme Corp  | 3     | $425.00 | Confirmed |

Answer

  ActiveAdmin.register Order do
    # Fixes the N+1 that the blocks below would otherwise cause
    controller do
      def scoped_collection
        super.includes(:customer, :line_items)
      end
    end

    index do
      selectable_column
      id_column

      column :customer, sortable: "customers.name" do |order|
        link_to order.customer.name, admin_customer_path(order.customer)
      end

      column("Items") { |order| order.line_items.size }

      column("Total", sortable: :total_cents) do |order|
        number_to_currency(order.total_cents / 100.0, unit: order.currency_symbol)
      end

      column :status do |order|
        status_tag order.status,
                   class: (order.cancelled? ? :error : :ok)
      end

      column("Age") { |order| "#{time_ago_in_words(order.created_at)} ago" }

      actions
    end

    # Same idea on the show page
    show do
      attributes_table do
        row :customer
        row("Total") { |o| number_to_currency(o.total_cents / 100.0) }
      end
    end
  end

Learn More

cdrrazan

Rajan Bhattarai

Full Stack Software Developer! 💻 🏡 Grad. Student, MCS. 🎓 Class of '23. GitKraken Ambassador 🇳🇵 2021/22. Works with Ruby / Rails. Photography when no coding. Also tweets a lot at TW / @cdrrazan!

Read More