Skip to content
Mohamed Abdul-Fattah edited this page Feb 16, 2022 · 21 revisions

Welcome to the Wiki for the Trestle Admin project!

Full documentation is coming soon.

FAQ

Q: How to set the Favicon?

A: In config/initializers/trestle.rb set config.favicon = "favicon.ico"

Q: How to rename the title of a resource view?

A: In config/locales/en.yml set en.admin.<model>.titles.index (see issue). For instance if you model is called AuthorityCard:

# config/locales/en.yml
en:
  admin:
     authority_cards:
        breadcrumbs:
          index: "Authority Cards"
        titles:
          index: "List of Authority cards"
        table:
          headers:
            auth: "Authority"

Similarly, to rename the header_text of a column in a resource admin table, set the translation for en.admin.<model>.table.headers.<column field name> (see code).

Q: How can I remove the Add / Delete Buttons?

A: You can remove default actions (e.g. create, destroy) from a resource like so:

Trestle.resource(:articles) do
  remove_action :destroy

This will result in the delete button no longer being present on the index or show pages.

Note that if you want to remove the "New resource" button to prevent resources from being created, you should remove both :new and :create:

Trestle.resource(:articles) do
  remove_action :new, :create

Q: How can I link back to a model in the main app?

A: If you need to create a button that brings you to the resource in the "frontend" using the Rails routes you can use the follow (given model is your admin instance):

# /app/admin/model_admin.rb
unless model.new_record?
  concat content_tag(:hr)
  concat link_to("Preview", Rails.application.routes.url_helpers.model_path(model), class: "btn btn-primary", target: :_blank)
end

Q: How can I add several separate resource admins for the same ActiveRecord model?

A: To add separate admin_resources create separate admin files and pass the model (Product in the example) as the model: parameter:

# app/admin/test_product_admin.rb
Trestle.resource(:test_product, model: Product) do
...
end

# app/admin/real_product_admin.rb
Trestle.resource(:real_product, model: Product) do
...
end

Source: Issue 370

Q: How can I append additional fields or a sidebar to the form without losing the default fields?

A: You can use the following

form do |item|
  concat Trestle::Form::Automatic.new(admin).render(self, item)
  # ... your additional fields/sidebar here ...
end

Note: This really concats the rendering output (html), so this approach does not work for tables.

Source: Issue 346

Q: How can I scope the records shown in a table view?

A: To show subsets of the collection you can add a scopes do block to your Admin Resource which show as buttons which restrict the collection:

Trestle.resource(:projects) do

  scopes do
    scope 'Finished projects', -> { Project.where(status: 'finished') }
    scope 'Active projects', -> { Project.where(status: 'active') }
    scope 'My projects', -> { Project.where(user: current_user) }
  end

end

Or more generically, if you have a model field which has a tag-like status:

Trestle.resource(:projects) do
  scopes do
    Project.distinct.pluck(:status).reject(&:blank?).each do |status|
      scope status, -> { Project.where(status: status) }
    end
  end
  ...

You can group the scopes by passing a group to the scope (see Issue 322):

Trestle.resource(:projects) do

 scopes do
   scope 'Finished', -> { Project.where(status: 'finished') }, group: 'Project status'
   scope 'Active', -> { Project.where(status: 'active') }, group: 'Project status'
   scope 'My projects', -> { Project.where(user: current_user) }, group: 'Other'
 end

end

You can also pass additional options to the scopes block to change the way the scopes are rendered:

The usage is effectively the same as in your example. Provide the group option on a scope to enable grouping, and additional options can be specified on the scopes call.

# By default scope groups are shown as rows. If `layout: :column` is passed, then groups are shown in columns.
scopes layout: :columns do
  ...
end

# Disable grouping regardless of scope definitions:
scopes group: false do
  ...
end

# Add custom html classes to the scopes block
scopes class: "scope-tags" do
  ...
end

Q: Is there a way to reuse table definitions?

A: Table definitions are available via the class method tables[:index] on the Admin Resource and can be reused by calling the builder method table with a name. For instance, if you want to create a tab in the admin view for the Project model, which shows the table from the TaskAdmin view:

Trestle.resource(:projects) do
  form do |project|
    # ...

    tab :tasks, badge: project.tasks.size do
      table TasksAdmin.tables[:index], collection: project.tasks # Re-use existing table from TasksAdmin
      concat admin_link_to("New Task", admin: :tasks, action: :new, params: { project_id: project }, class: "btn btn-success")
    end
  end
end

This is equivalent to:

Trestle.resource(:projects) do
  form do |project|
    tab :project do
      text_field :name
      text_area :description
    end

    tab :tasks, badge: project.tasks.size do
      table project.tasks, admin: :tasks do
        column :description, link: true
        column :done, align: :center
        column :created_at, align: :center
        actions
      end

      concat admin_link_to("New Task", admin: :tasks, action: :new, params: { project_id: project }, class: "btn btn-success")
    end
  end
end

Note: This requires the top-level resource and table to be explicitly defined (an implicit table won't work):

Trestle.resource(:tasks) do
  table do # This defines TasksAdmin.tables[:index]
    column :description, link: true
    column :done, align: :center
    column :created_at, align: :center
    actions
  end
end

In many cases, your top-level table might include additional columns that you don't want to show on the sub-resource. In this you can define additional name tables on the top-level resource and reference them from the child resource.

Trestle.resource(:tasks) do
  # Default table (:index)
  table do
    column :project
    column :description, link: true
    column :done, align: :center
    column :created_at, align: :center
    actions
  end

  # Named table
  table :project do
    column :description, link: true
    column :done, align: :center
    column :created_at, align: :center
    actions
  end
end

This keeps all of the table definitions in the one place.

Source: Issue 346

Q: How can I start with customizing the table definition?

A: When you add a table do ... end into your admin resource then the automatically generated columns will disappear. To get back to those default columns you can use the following code and copy the resulting text from your Rails log:

# /app/admin/<your model>_admin.rb
Trestle.resource(:<your model>) do
  controller do 
    def index
      print_table
    end

    def print_table
      Rails.logger.silence do
        puts "table do"
        admin.default_table_attributes.map.with_index do |attribute, index|
          case attribute.type
          when :association
            puts "  column #{attribute.association_name.to_sym.inspect}, sort: false"
          else
            puts "  column #{attribute.name.to_sym.inspect}#{", link: true" if index.zero?}#{", align: :center" if [:datetime, :boolean].include?(attribute.type)}"
          end
        end
        puts "  actions"
        puts "end"
      end
    end
  end
end

Q: How can I adjust the pagination?

A: You can customize the items per page by adding paginates_per 20 to your model.

class Foo < ApplicationRecord
  belongs_to :bar

  paginates_per 20
end

Q: How can I adjust the rendering/representation/display of a column value?

A: By default Trestle will use the format_helper.rb to render a value. This allows for the following:

  • You can pass options for :currency and :tags to force rendering.
  • If the value is a ActiveModel instance (or more precisely something which responds to :id), the value is checked if it responds to one of the following methods (see config.display_methods): [:display_name, :full_name, :name, :title, :username, :login, :email] If the objects responds, then this will be used as the value otherwise to_s is used.
  • You can adjust the value to be rendered by passing a block to the column definition where you make from the object instance being displayed in the current row to the value to display.