cachingruby-on-rails-4activeadminarbre

Row level caching with "Index as Table"


I am displaying a table with ActiveAdmin using the "Index as Table" functionality:

index :pagination_total => false do

    if Ability.new(current_user).can? :manage, :metric
        selectable_column
    end

    column '' do |metric|
        links = link_to(metric.icon, admin_metric_path(metric), :title => metric.comment)
        links += link_to(metric.data_icon, admin_metric_path(metric)) unless metric.datum_ids.empty?
        links
    end

    column 'Status', :success, sortable: :success do |metric|
        metric.success == 1 ? status_tag('Success', :ok) : status_tag('FAILED', :error)
    end
    column 'When (UTC)', :createddttm
    column 'What', :metric_name
    column 'Area',    :logarea
    column 'Subarea', :subarea
    column 'Value',   :value
    column 'Machine', :machine_name, sortable: 'machinename.machinename'
    column 'Domain',  :domain_name, sortable: 'domain.domainname'
    column 'Product', :product_name, sortable: 'product.productname'
    column 'Version', :product_version, sortable: 'product.productversion'
    column 'Install Type', :install_type, sortable: 'product.productinstalltype'
    column 'Lang', :language
    column 'Duration', :duration
end

Given that the row data does not change, I would like to add row level caching of the rendered html with a long expiry time but I can't figure out how to hook into the row rendering code in Arbre.

I am currently caching the entire page for 60 seconds but that is not optimal. My cache store is Dalli / memcached.


Solution

  • UPDATE 2:

    Try this with the cashed_rows method:

    # lib\active_admin\views\index_as_table.rb
    module ActiveAdmin
      module Views
        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 = table_for collection, table_options do |t|
              table_config_block = page_presenter.block || default_table
              instance_exec(t, &table_config_block)
            end
    
            #new code
            rows = []
            table.children.each {|row| rows << row.to_s}
            resource_class.cached_rows = rows 
    
            table
          end
        end
      end
    end
    

    UPDATE: This is a monkey patch. Create a new file in lib folder, then you can use the rows array.

    module ActiveAdmin
      module Views
        class TableFor < Arbre::HTML::Table
    
          def build_table_body
    
            @tbody = tbody do
              # Build enough rows for our collection
              @collection.each do |elem|
                classes = [cycle('odd', 'even')]
    
                if @row_class
                  classes << @row_class.call(elem)
                end
    
                tr(class: classes.flatten.join(' '), id: dom_id_for(elem))
              end
            end
    
            #new code: rows will contain the html string for each row
            rows = []
            @tbody.children.each {|row| rows << row.to_s} #you can also use: @tbody.to_s
            YourActiveRecordModel.cached_rows= rows
    
            @tbody 
          end
        end
      end
    end
    

    class YourActiveRecordModel < ActiveRecord::Base
    
      def self.cached_rows=(attr)
        @@rows = attr
      end
    
      def self.cached_rows
        @@rows
      end
    end
    

    Now you can get the html string: YourActiveRecordModel.cached_rows if you build the index table at least once.

    Old answer:

    I would make a new table that contains the string representation of the contained objects. You can determine which record want to load (the original or the cached record):

      controller do
        def find_resource
          if params[:action] == 'index' #or something similar
             CachedRecords.find(params[:id])
          elsif params[:action] == 'edit'
             OriginalRecords.find(params[:id])
        end
      end
    

    https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#customizing-resource-retrieval