module ActiveAdmin module Views # # Index as a Table # # By default, the index page is a table with each of the models content columns and links to # show, edit and delete the object. There are many ways to customize what gets # displayed. # # ## Defining Columns # # To display an attribute or a method on a resource, simply pass a symbol into the # column method: # # ```ruby # index do # selectable_column # column :title # end # ``` # # For association columns we make an educated guess on what to display by # calling the following methods in the following order: # # ```ruby # :display_name, :full_name, :name, :username, :login, :title, :email, :to_s # ``` # # This can be customized in `config/initializers/active_admin.rb`. # # If the default title does not work for you, pass it as the first argument: # # ```ruby # index do # selectable_column # column "My Custom Title", :title # end # ``` # # Sometimes that just isn't enough and you need to write some view-specific code. # For example, say we wanted a "Title" column that links to the posts admin screen. # # `column` accepts a block that will be rendered for each of the objects in the collection. # The block is called once for each resource, which is passed as an argument to the block. # # ```ruby # index do # selectable_column # column "Title" do |post| # link_to post.title, admin_post_path(post) # end # end # ``` # # ## Defining Actions # # To setup links to View, Edit and Delete a resource, use the `actions` method: # # ```ruby # index do # selectable_column # column :title # actions # end # ``` # # You can also append custom links to the default links: # # ```ruby # index do # selectable_column # column :title # actions do |post| # item "Preview", admin_preview_post_path(post), class: "member_link" # end # end # ``` # # Or forego the default links entirely: # # ```ruby # index do # column :title # actions defaults: false do |post| # item "View", admin_post_path(post) # end # end # ``` # # Or append custom action with custom html via arbre: # # ```ruby # index do # column :title # actions do |post| # a "View", href: admin_post_path(post) # end # end # ``` # # In case you prefer to list actions links in a dropdown menu: # # ```ruby # index do # selectable_column # column :title # actions dropdown: true do |post| # item "Preview", admin_preview_post_path(post) # end # end # ``` # # In addition, you can insert the position of the row in the greater # collection by using the index_column special command: # # ```ruby # index do # selectable_column # index_column # column :title # end # ``` # # index_column take an optional offset parameter to allow a developer to set # the starting number for the index (default is 1). # # ## Sorting # # When a column is generated from an Active Record attribute, the table is # sortable by default. If you are creating a custom column, you may need to give # Active Admin a hint for how to sort the table. # # You can pass the key specifying the attribute which gets used to sort objects using Active Record. # By default, this is the column on the resource's table that the attribute corresponds to. # Otherwise, any attribute that the resource collection responds to can be used. # # ```ruby # index do # column :title, sortable: :title do |post| # link_to post.title, admin_post_path(post) # end # end # ``` # # You can turn off sorting on any column by passing false: # # ```ruby # index do # column :title, sortable: false # end # ``` # # It's also possible to sort by PostgreSQL's hstore column key. You should set `sortable` # option to a `column->'key'` value: # # ```ruby # index do # column :keywords, sortable: "meta->'keywords'" # end # ``` # # ## Custom sorting # # It is also possible to use database specific expressions and options for sorting by column # # ```ruby # order_by(:title) do |order_clause| # if order_clause.order == 'desc' # [order_clause.to_sql, 'NULLS LAST'].join(' ') # else # [order_clause.to_sql, 'NULLS FIRST'].join(' ') # end # end # # index do # column :title # end # ``` # # ## Associated Sorting # # You're normally able to sort columns alphabetically, but by default you # can't sort by associated objects. Though with a few simple changes, you can. # # Assuming you're on the Books index page, and Book has_one Publisher: # # ```ruby # controller do # def scoped_collection # super.includes :publisher # prevents N+1 queries to your database # end # end # ``` # # Then it's simple to sort by any Publisher attribute from within the index table: # # ```ruby # index do # column :publisher, sortable: 'publishers.name' # end # ``` # # ## Showing and Hiding Columns # # The entire index block is rendered within the context of the view, so you can # easily do things that show or hide columns based on the current context. # # For example, if you were using CanCan: # # ```ruby # index do # column :title, sortable: false # column :secret_data if can? :manage, Post # end # ``` # # ## Custom row class # # In order to add special class to table rows pass the proc object as a `:row_class` option # of the `index` method. # # ```ruby # index row_class: ->elem { 'active' if elem.active? } do # # columns # end # ``` # class IndexAsTable < ActiveAdmin::Component def build(page_presenter, collection) table_options = { id: "index_table_#{active_admin_config.resource_name.plural}", sortable: true, class: "index_table index", i18n: active_admin_config.resource_class, paginator: page_presenter[:paginator] != false, row_class: page_presenter[:row_class] } table_for collection, table_options do |t| table_config_block = page_presenter.block || default_table instance_exec(t, &table_config_block) end end def table_for(*args, &block) insert_tag IndexTableFor, *args, &block end def default_table proc do selectable_column id_column if resource_class.primary_key active_admin_config.resource_columns.each do |attribute| column attribute end actions end end def self.index_name "table" end # # Extend the default ActiveAdmin::Views::TableFor with some # methods for quickly displaying items on the index page # class IndexTableFor < ::ActiveAdmin::Views::TableFor # Display a column for checkbox def selectable_column return unless active_admin_config.batch_actions.any? column resource_selection_toggle_cell, class: 'col-selectable', sortable: false do |resource| resource_selection_cell resource end end def index_column(start_value = 1) column '#', class: 'col-index', sortable: false do |resource| @collection.offset_value + @collection.index(resource) + start_value end end # Display a column for the id def id_column raise "#{resource_class.name} has no primary_key!" unless resource_class.primary_key column(resource_class.human_attribute_name(resource_class.primary_key), sortable: resource_class.primary_key) do |resource| if controller.action_methods.include?('show') link_to resource.id, resource_path(resource), class: "resource_id_link" elsif controller.action_methods.include?('edit') link_to resource.id, edit_resource_path(resource), class: "resource_id_link" else resource.id end end end def default_actions raise '`default_actions` is no longer provided in ActiveAdmin 1.x. Use `actions` instead.' end # Add links to perform actions. # # ```ruby # # Add default links. # actions # # # Add default links with a custom column title (empty by default). # actions name: 'A title!' # # # Append some actions onto the end of the default actions. # actions do |admin_user| # item 'Grant Admin', grant_admin_admin_user_path(admin_user) # item 'Grant User', grant_user_admin_user_path(admin_user) # end # # # Append some actions onto the end of the default actions using arbre dsl. # actions do |admin_user| # a 'Grant Admin', href: grant_admin_admin_user_path(admin_user) # end # # # Custom actions without the defaults. # actions defaults: false do |admin_user| # item 'Grant Admin', grant_admin_admin_user_path(admin_user) # end # # # Append some actions onto the end of the default actions displayed in a Dropdown Menu # actions dropdown: true do |admin_user| # item 'Grant Admin', grant_admin_admin_user_path(admin_user) # end # # # Custom actions without the defaults displayed in a Dropdown Menu. # actions defaults: false, dropdown: true, dropdown_name: 'Additional actions' do |admin_user| # item 'Grant Admin', grant_admin_admin_user_path(admin_user) # end # # ``` def actions(options = {}, &block) name = options.delete(:name) { '' } defaults = options.delete(:defaults) { true } dropdown = options.delete(:dropdown) { false } dropdown_name = options.delete(:dropdown_name) { I18n.t 'active_admin.dropdown_actions.button_label', default: 'Actions' } options[:class] ||= 'col-actions' column name, options do |resource| if dropdown dropdown_menu dropdown_name do defaults(resource) if defaults instance_exec(resource, &block) if block_given? end else table_actions do defaults(resource, css_class: :member_link) if defaults if block_given? block_result = instance_exec(resource, &block) text_node block_result unless block_result.is_a? Arbre::Element end end end end end private def defaults(resource, options = {}) localizer = ActiveAdmin::Localizers.resource(active_admin_config) if controller.action_methods.include?('show') && authorized?(ActiveAdmin::Auth::READ, resource) item localizer.t(:view), resource_path(resource), class: "view_link #{options[:css_class]}", title: localizer.t(:view) end if controller.action_methods.include?('edit') && authorized?(ActiveAdmin::Auth::UPDATE, resource) item localizer.t(:edit), edit_resource_path(resource), class: "edit_link #{options[:css_class]}", title: localizer.t(:edit) end if controller.action_methods.include?('destroy') && authorized?(ActiveAdmin::Auth::DESTROY, resource) item localizer.t(:delete), resource_path(resource), class: "delete_link #{options[:css_class]}", title: localizer.t(:delete), method: :delete, data: { confirm: localizer.t(:delete_confirmation) } end end class TableActions < ActiveAdmin::Component builder_method :table_actions def item *args text_node link_to *args end end end # IndexTableFor end end end