Customizing Dashboards
In order to customize which attributes get displayed for each resource, edit the dashboard file generated by the installation generator.
By default, the file will look something like this:
require "administrate/base_dashboard"
class CustomerDashboard < Administrate::BaseDashboard
ATTRIBUTE_TYPES = {
id: Field::Number,
name: Field::String,
email: Field::String,
created_at: Field::DateTime,
updated_at: Field::DateTime,
orders: Field::HasMany,
}
COLLECTION_ATTRIBUTES = [
:id,
:name,
:email,
:created_at,
:updated_at,
:orders,
]
SHOW_PAGE_ATTRIBUTES = [
:id,
:name,
:email,
:created_at,
:updated_at,
:orders,
]
FORM_ATTRIBUTES = [
:name,
:email,
:orders,
]
end
To change which attributes appear on each of the index
, show
, and edit
pages, add or remove attributes to each constant array.
Finally, the ATTRIBUTE_TYPES
method defines how each attribute is displayed
throughout the dashboard. There are a number of Field
classes that you can
specify, including:
Field::BelongsTo
Field::Boolean
Field::DateTime
Field::Date
Field::Email
Field::HasMany
Field::HasOne
Field::Number
Field::Polymorphic
Field::Select
Field::String
Field::Text
Field::Url
Field::Password
Customizing Fields
Setting Options
Each of the Field
types take a different set of options,
which are specified through the .with_options
class method:
Field::BelongsTo
:order
- Specifies the column used to order the records. It will apply both in
the table views and in the dropdown menu on the record forms.
You can set multiple columns as well with direction. E.g.: "name, email DESC"
.
:scope
- Specifies a custom scope inside a callable. Useful for preloading.
Example #1: .with_options(scope: -> { MyModel.includes(:rel).limit(5) })
Example #2: .with_options(scope: -> (field) { field.resource.my_models.includes(:rel).limit(5) })
:include_blank
- Specifies if the select element to be rendered should include
blank option. Default is true
.
:searchable
- Specify if the attribute should be considered when searching.
Default is false
.
searchable_fields
- Specify which columns to use on the search, only applies
if searchable
is true
For example:
country: Field::BelongsTo.with_options(
searchable: true,
searchable_fields: ['name'],
)
with this, you will be able to search through the column name
from the
association belongs_to :country
, from your model.
:class_name
- Specifies the name of the associated class.
:primary_key
(deprecated) - Specifies the association's primary_key.
:foreign_key
(deprecated) - Specifies the name of the foreign key directly.
Field::HasMany
:collection_attributes
- Set the columns to display in the show view.
Default is COLLECTION_ATTRIBUTES in dashboard.
:limit
- The number of resources (paginated) to display in the show view. To disable pagination,
set this to 0
or false
. Default is 5
.
:sort_by
- What to sort the association by in the show view.
:direction
- What direction the sort should be in, :asc
(default) or :desc
.
:class_name
- Specifies the name of the associated class.
:primary_key
(deprecated) - Specifies object's primary_key.
:foreign_key
(deprecated) - Specifies the name of the foreign key directly.
Field::HasOne
:order
- Specifies the column used to order the records. It will apply both in
the table views and in the dropdown menu on the record forms.
You can set multiple columns as well with direction. E.g.: "name, email DESC"
.
:searchable
- Specify if the attribute should be considered when searching.
Default is false
.
searchable_fields
- Specify which columns to use on the search, only applies if
searchable
is true
For example:
city: Field::HasOne.with_options(
searchable: true,
searchable_fields: ['name'],
)
with this, you will be able to search through the column name
from the
association has_one :city
, from your model.
:class_name
- Specifies the name of the associated class.
Field::Number
:searchable
- Specify if the attribute should be considered when searching.
Note that currently number fields are searched like text, which may yield
more results than expected. Default is false
.
:decimals
- Set the number of decimals to display. Defaults to 0
.
:prefix
- Prefixes the number with a string. Defaults to ""
.
:suffix
- Suffixes the number with a string. Defaults to ""
.
:format
- Specify a hash which defines a formatter. This uses ActiveSupport
and works by by passing a hash that includes the formatter (formatter
) and
the options for the formatter (formatter_options
). Defaults to the locale's
delimiter when formatter_options
does not include a delimiter
. See the
example below. All helpers from ActiveSupport::NumberHelper
are supported.
For example, you might use the following to display U.S. currency:
unit_price: Field::Number.with_options(
prefix: "$",
decimals: 2,
)
# "$5.99"
Or, to display a distance in kilometers, using a space as the delimiter:
distance: Field::Number.with_options(
suffix: " km",
decimals: 2,
format: {
formatter: :number_to_delimited,
formatter_options: {
delimiter: ' ',
},
},
)
# "2 000.00 km"
Field::Polymorphic
:classes
- Specify a list of classes whose objects will be used to populate select boxes for editing this polymorphic field.
Default is []
.
:order
- What to sort the association by in the form select.
Default is nil
.
Field::DateTime
:format
- Specify what format, using strftime
you would like DateTime
objects to display as.
:timezone
- Specify which timezone Date
and DateTime
objects are based
in.
Field::Date
:format
- Specify what format, using strftime
you would like Date
objects to display as.
Field::Select
:collection
- The options available to select. The format is the same as for Rails's own options_for_select
.
If the given value responds to call
, this will be called and the result used instead. The call will receive an instance of the field as argument. For example:
confirmation: Field::Select.with_options(
collection: ->(field) {
person = field.resource
{
"no, #{person.name}" => "opt0",
"yes, #{person.name}" => "opt1",
"absolutely, #{person.name}" => "opt2",
}
},
)
Administrate will detect if the attribute is an ActiveRecord::Enum
and extract the available options. Note that if a collection
is provided it will take precedence.
If no collection is provided and no enum can be detected, the list of options will be empty.
:searchable
- Specify if the attribute should be considered when searching.
Default is true
.
:include_blank
- Similar to the option of the same name accepted by Rails helpers. If provided, a "blank" option will be added first to the list of options, with the value of include_blank
as label.
Field::String
:searchable
- Specify if the attribute should be considered when searching.
Default is true
.
:truncate
- Set the number of characters to display in the index view.
Defaults to 50
.
Field::Text
:searchable
- Specify if the attribute should be considered when searching.
Default is false
.
:truncate
- Set the number of characters to display in the index view.
Defaults to 50
.
:input_options
- Options to customize the text area in form view.
Example: .with_options(input_options: { rows: 20 })
Field::Url
:searchable
- Specify if the attribute should be considered when searching.
Default is true
.
:truncate
- Set the number of characters to display in the index view.
Defaults to 50
.
:html_options
- Specify anchor tag attributes (e.g., target="_blank"
).
Defaults is {}
.
Field::Password
:searchable
- Specify if the attribute should be considered when searching.
Default is false
.
:truncate
- Set the number of characters to display in the views.
Defaults to 50
.
:character
- Set the replace character.
Defaults to •
.
Defining Labels
To change the user-facing label for an attribute, define a custom I18n translation:
en:
helpers:
label:
customer:
name: Full Name
To change the labels used for resources in dashboard collections. Assume you have a users dashboard and you want to change "User #1" to "Testy McTesterson", the user's name.
Add this method to the dashboard for Users. Use whatever attribute or method you like. Example for user:
def display_resource(user)
user.name
end
To change the dashboard name in sidebar menu, sub-header and search string use default ActiveRecord i18n translations for models:
en:
activerecord:
models:
customer:
one: Happy Customer
other: Happy Customers
Collection Filters
Resources can be filtered with pre-set filters. For example if we added:
COLLECTION_FILTERS = {
inactive: ->(resources) { resources.where("login_at < ?", 1.week.ago) }
}
…to a dashboard, we can query the resources of that dashboard with:
bob inactive:
…to find users named "bob" who hasn't logged in the last week.
If you already had the inactive
scope you could define the filter like so to
take advantage of existing ActiveRecord scopes (and other class methods on the
resource class).
COLLECTION_FILTERS = {
inactive: ->(resources) { resources.inactive }
}
You can also define a filter with parameters:
COLLECTION_FILTERS = {
state: ->(resources, attr) { resources.where(state: attr) }
}
You can now search your resource with 'state:open' and your collection filter Proc will be called with with attr = open.
Form Attributes
You can define different attributes for new/create or edit/update actions:
FORM_ATTRIBUTES_NEW = [
:name,
:email
]
FORM_ATTRIBUTES_EDIT = [
:name,
:email,
:orders
]
Or for custom action with constant name "FORM_ATTRIBUTES_#{action.upcase}"
Form Fields' Hints
You can show a brief text element below an input field by setting the corresponding translation key using the path:
administrate.field_hints.#{model_name}.#{field_name}
For example, with a Customer dashboard with an email field you can add a string value that will be used as text hint:
en:
administrate:
field_hints:
customer:
email: field_hint
Grouped Attributes
You may have models with a large number of fields and therefore you might want to group them in a meaningul way:
class UserDashboard < Administrate::BaseDashboard
SHOW_PAGE_ATTRIBUTES = {
"" => [:username],
"Personal Information" => [:first_name, :last_name, :email],
"Address" => [:address_line_one, :address_line_two, :address_city, :address_state, :address_country]
}
FORM_ATTRIBUTES = {
"" => [:username, :password, :password_confirmation],
"personal_information" => [:first_name, :last_name, :email],
"address" => [:address_line_one, :address_line_two, :address_city, :address_state, :address_country]
}
end
You can optionally translate your group labels:
en:
helpers:
label:
user:
address: Address
personal_information: Personal Information
If not defined (see SHOW_PAGE_ATTRIBUTES
above), Administrate will default to the given strings.
Virtual Attributes
For all field types, you can use the getter
option to change where the data is retrieved from or to set the data directly.
By using this, you can define an attribute in ATTRIBUTE_TYPES
that doesn’t exist in the model, and use it for various purposes.
Attribute Aliases
You can create an alias for an attribute. For example:
ATTRIBUTE_TYPES = {
shipped_at: Field::DateTime,
shipped_on: Field::Date.with_options(
getter: :shipped_at
)
}
COLLECTION_ATTRIBUTES = [
:shipped_on
}
SHOW_PAGE_ATTRIBUTES = [
:shipped_at
}
In this example, a virtual attribute shipped_on
based on the value of shipped_at
is defined as a Date
type and used for display on the index page (this can help save table cell space).
Decorated Attributes
You can also use this to decorate data. For example:
ATTRIBUTE_TYPES = {
price: Field::Number,
price_including_tax: Field::Number.with_options(
getter: -> (field) {
field.resource.price * 1.1 if field.resource.price.present?
}
)
}
Composite Attributes
You can dynamically create a virtual attribute by combining multiple attributes for display. For example:
ATTRIBUTE_TYPES = {
first_name: Field::String,
last_name: Field::String,
full_name: Field::String.with_options(
getter: -> (field) {
[
field.resource.first_name,
field.resource.last_name
].compact_blank.join(' ')
}
)
}
Virtual Fields
Custom fields can also be defined using virtual fields.
ATTRIBUTE_TYPES = {
id: Field::Number,
receipt: Field::ReceiptLink
}
module Administrate
module Field
class ReceiptLink < Base
def data
resource.id
end
def filename
"receipt-#{data}.pdf"
end
def url
"/files/receipts/#{filename}"
end
end
end
end
<%= link_to field.filename, field.url %>
Custom Actions via Virtual Field
By creating custom fields that are not dependent on specific attributes, you can insert custom views into any screen. For example, you can add custom buttons like this:
ATTRIBUTE_TYPES = {
id: Field::Number,
custom_index_actions: Field::CustomActionButtons,
custom_show_actions: Field::CustomActionButtons,
}
module Administrate
module Field
class CustomActionButtons < Base
def data
resource.id
end
end
end
end
<%# app/views/fields/custom_action_buttons/_index.html.erb %>
<% if field.data.present? %>
<%= button_to "some action 1", [:some_action_1, namespace, field.resource] %>
<%= button_to "some action 2", [:some_action_2, namespace, field.resource] %>
<%= button_to "some action 3", [:some_action_3, namespace, field.resource] %>
<% end %>