Skip to content

Instantly share code, notes, and snippets.

@tinynumbers
Last active April 21, 2024 08:57
Show Gist options
  • Save tinynumbers/5896537 to your computer and use it in GitHub Desktop.
Save tinynumbers/5896537 to your computer and use it in GitHub Desktop.
ActiveAdmin controller extension to persist resource index filters between requests.
# this stuff goes in config/initializers/active_admin.rb
ActiveAdmin.setup do |config|
# ...
# put these lines in the "Controller Filters" section of the ActiveAdmin.setup block
# These two are defined in ActiveAdmin::FilterSaver::Controller, which is loaded below.
config.before_filter :restore_search_filters
config.after_filter :save_search_filters
# ...
end
# put the following lines below the main ActiveAdmin.setup block (also in config/initializers/active_admin.rb)
require 'active_admin/filter_saver/controller'
ActiveAdmin.before_load do |app|
# Add our Extensions
ActiveAdmin::BaseController.send :include, ActiveAdmin::FilterSaver::Controller
end
# -*- encoding : utf-8 -*-
# put this in lib/active_admin/filter_saver/controller.rb
module ActiveAdmin
module FilterSaver
# Extends the ActiveAdmin controller to persist resource index filters between requests.
#
# @author David Daniell / тιηуηυмвєяѕ <info@tinynumbers.com>
module Controller
private
SAVED_FILTER_KEY = :last_search_filter
def restore_search_filters
filter_storage = session[SAVED_FILTER_KEY]
if params[:clear_filters].present?
params.delete :clear_filters
if filter_storage
logger.info "clearing filter storage for #{controller_key}"
filter_storage.delete controller_key
end
if request.post?
# we were requested via an ajax post from our custom JS
# this render will abort the request, which is ok, since a GET request will immediately follow
render json: { filters_cleared: true }
end
elsif filter_storage && params[:action].to_sym == :index && params[:q].blank?
saved_filters = filter_storage[controller_key]
unless saved_filters.blank?
params[:q] = saved_filters
end
end
end
def save_search_filters
if params[:action].to_sym == :index
session[SAVED_FILTER_KEY] ||= Hash.new
session[SAVED_FILTER_KEY][controller_key] = params[:q]
end
end
# Get a symbol for keying the current controller in the saved-filter session storage.
def controller_key
#params[:controller].gsub(/\//, '_').to_sym
current_path = request.env['PATH_INFO']
current_route = Rails.application.routes.recognize_path(current_path)
current_route.sort.flatten.join('-').gsub(/\//, '_').to_sym
end
end
end
end
# put this in e.g. app/assets/javascripts/admin/index-filters.coffee
# and include this in app/assets/javascripts/active_admin.js
$ ->
# Extend the clear-filters button to clear saved filters
$('.clear_filters_btn').click (evt) ->
# This will send a synchronous post with clear_filters set to true -
# our AA FilterSaver controller extension looks for this parameter to
# know when to clear session-stored filters for a resource - and then
# the default AA clear-filters button behavior will issue a get request
# to actually re-render the page.
$.ajax this.href, {
async: false,
data: { clear_filters: true },
type: 'POST'
}
@sonniimukh
Copy link

I ended up with the original solution and the following JS approach which is more clear and follows the logic of native Clear Filters action:

$ ->
  # Clear Filters button
  $('.clear_filters_btn').off('click')
  $('.clear_filters_btn').click (e) ->
    params = window.location.search.slice(1).split('&')
    regex = /^(q\[|q%5B|q%5b|page|commit)/
    if typeof Turbolinks != 'undefined'
      Turbolinks.visit(window.location.href.split('?')[0] + '?clear_filters=1&' + (param for param in params when not param.match(regex)).join('&'))
      e.preventDefault()
    else
      window.location.search = 'clear_filters=1&' + (param for param in params when not param.match(regex)).join('&')

Had also to apply the Devise workaround proposed by @elsurudo.

Other than that works perfectly fine on top of Rails 5.1.4 and ActiveAdmin 1.1.0.

Thanks all!

@mirelon
Copy link

mirelon commented Dec 1, 2017

Rails 5.0.6:
controller key needs to return string instead of symbol:

      # Get a symbol for keying the current controller in the saved-filter session storage.
      def controller_key
        #params[:controller].gsub(/\//, '_').to_sym
        current_path = request.env['PATH_INFO']
        current_route = Rails.application.routes.recognize_path(current_path)
        current_route.sort.flatten.join('-').gsub(/\//, '_')
      end

@Sprachprofi
Copy link

Thank you all! The following is a complete working implementation for Rails 7 and vanilla JS:

add this to config/initializers/active_admin.rb

ActiveAdmin.setup do |config|
  ...
  config.before_action :restore_search_filters
  config.after_action :save_search_filters
  ...
end

require 'active_admin/filter_saver/controller'

ActiveAdmin.before_load do |app|
  # Add our Extensions
  ActiveAdmin::BaseController.send :include, ActiveAdmin::FilterSaver::Controller
end

new file: /lib/active_admin/filter_saver/controller.rb

# -*- encoding : utf-8 -*-
module ActiveAdmin
  module FilterSaver

    # Extends the ActiveAdmin controller to persist resource index filters between requests.
    #
    # @author David Daniell / тιηуηυмвєяѕ <info@tinynumbers.com>
    # improvements by tlueker and mirelon
    module Controller

      private

      SAVED_FILTER_KEY = :last_search_filter

      def restore_search_filters
        filter_storage = session[SAVED_FILTER_KEY]
        if params[:clear_filters].present? || (params["commit"].present? && params["commit"] == "Filter")
          params.delete :clear_filters
          if filter_storage
            logger.info "clearing filter storage for #{controller_key}"
            filter_storage.delete controller_key
          end
          if request.post?
            # we were requested via an ajax post from our custom JS
            # this render will abort the request, which is ok, since a GET request will immediately follow
            render json: { filters_cleared: true }
          end
        elsif filter_storage && params[:action].to_sym == :index && params[:q].blank? && (params["commit"].blank? || params["commit"] != "Filter")
          saved_filters = filter_storage[controller_key]
          unless saved_filters.blank?
            params[:q] = saved_filters
          end
        end
      end

      def save_search_filters
        if params[:action].to_sym == :index
          session[SAVED_FILTER_KEY] ||= Hash.new
          session[SAVED_FILTER_KEY][controller_key] = params[:q]
        end
      end

      # Get a symbol for keying the current controller in the saved-filter session storage.
      def controller_key
        #params[:controller].gsub(/\//, '_').to_sym
        current_path = request.env['PATH_INFO']
        current_route = Rails.application.routes.recognize_path(current_path)
        current_route.sort.flatten.join('-').gsub(/\//, '_')
      end

    end

  end
end

add this to the bottom of active_admin.js or into an imported javascript file

$(document).ready(function() {
  $('.clear_filters_btn').on('click', function() {
      $.ajax(this.href, {
        async: false,
        data: { clear_filters: true },
        type: 'POST'
      });
    });
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment