Skip to main content Link Menu Expand (external link) Copy Copied

Customizing your index and show pages

Customizing the #index page

After generating the controller, we’ll need to update it by adding method called #display_schema. It’ll return an instance of Super::Display. Let’s start with Admin::ProductsController.

class Admin::ProductsController < AdminController
  private

  def model
    Product
  end

  def display_schema
    Super::Display.new do |f, type|
    end
  end
end

Once you save that and reload the page, you won’t see any data columns, only an “Actions” column.

The f variable is similar to a Hash where the key is the column name and the value is the rule we use to turn it into a human readable value.

With that in mind, let’s manually make it look like it used to.

def display_schema
  Super::Display.new do |f, type|
    f[:name] = type.string
    f[:price_cents] = type.string
  end
end

We see there that strangely, that the type for price_cents is string and not integer. The string here should be thought of as to_s, not the actual type of the column.

It’s a little unnatural to show prices in cents; here where I live, we usually communicate in dollars. So let’s try formatting this a bit differently.

def display_schema
  Super::Display.new do |f, type|
    f[:name] = type.string
    f[:price_cents] = type.real { |column_value| "$#{sprintf("%.2f", column_value)}" }
  end
end

By choosing type.real, we’re telling Super that :price_cents is a database column and is thus filterable.

You’ll notice though that the name of the column still reads Price cents. Here’s one way we can get around that.

def display_schema
  Super::Display.new do |f, type|
    f[:name] = type.string
    f[:price] = type.computed(:record) { |record| "$#{sprintf("%.2f", record.price_cents)}" }
  end
end

Since we’ve specified type.computed here, Super knows not to attempt to search using the price column. Both computed and real accept arguments which tell it what to yield into your block: :column is the default and it yields the value of the column (it doesn’t have to be a column, just a method on the object), :record yields the entire record itself, and :none doesn’t yield anything.

Customizing the #show page

Customizing this page is identical to the #index page. However, #index pages tend to highlight some important fields while the #show page might show every field.

Let’s start with a controller that already has the #index view set up.

class Admin::CustomersController < AdminController
  private

  def model
    Customer
  end

  def display_schema
    Super::Display.new do |f, type|
      f[:name] = type.string
      if current_action.show?
        f[:receipt_count] = f.computed(:record) { |record| record.receipts.size }
      end
    end
  end
end

To add a field to only the #show page, we’ll use the #current_action method that’s already defined in the controller. With this, we can specify what data to show in the different pages.

def display_schema
  Super::Display.new do |f, type|
    f[:name] = type.string
    if current_action.show?
      f[:receipt_count] = f.computed(:record) { |record| record.receipts.size }
    end
  end
end

Showing a field on only the #index page is similar too, you can check for current_action.index?.

Note that this is just Ruby, so if you define a method like #current_admin, you can show some fields to some users while hiding it for others. You can customize this however you wish!

Supported display types

  • #real
  • #computed
  • #string
  • #timestamp
  • #time
  • #rich_text (ActionText)
  • #badge
  • #actions