-
-
Save tinynumbers/5896537 to your computer and use it in GitHub Desktop.
# 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 / тιηуηυмвєяѕ <[email protected]> | |
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' | |
} |
Rails 4.1.8 not work!
Fix
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_s
end
controller_key must return a string
On an active_admin resource that does not accept POST requests, the clear_filters button will fail. In my case, I fixed this to add a dummy route and controller action.
Is there a way for the clear_filters enable POST requests if they are not already enabled?
Thank you @tinynumbers. After @vincenzodev's suggestion seems to work in 4.2.0 as well.
To make clear filters also work for CSV downloads, I added the following lines:
filter_storage.delete "#{controller_key}-format-csv".to_sym
filter_storage.delete "#{controller_key}-format-xml".to_sym
filter_storage.delete "#{controller_key}-format-json".to_sym
How can we get session result in resource model?
Hi,
I follow the above instruction.
I have add the
active_admin.rb, controller.rb, index-filters.coffee
to my code base.
But I found restore_search_filters is not called.
the params[:q] is nil.
who can help to tell me what's missing ?
Thanks.
user.rb
ActiveAdmin.register User do
menu parent: 'User Management'
config.filters = false
controller do
before_filter :filter_params, only: [:index]
before_filter :restore_search_filters, only: [:batch_update]
after_filter :save_search_filters, only: [:index]
def batch_update(ids, state)
updated_user = []
users = User.find(ids)
users.each do |user|
if user.update state: User::STATES.index(state.to_sym)
updated_user << "##{user.id} "
else
flash[:alert] << "##{user.id} update failed."
end
end
flash[:alert] = "You have successfully changed the state to #{state} for #{updated_user.size} #{'user'.pluralize(updated_user.size)}"
params[:q] = restore_search_filters
redirect_to admin_users_path(params[:q])
end
def filter_params
@filter_params ||= params[:admin_users] || {}
end
end
the filter in the view:
filters.html.erb
<%= semantic_form_for :admin_users, url: admin_users_path, method: :get, html: { class: 'filter_form' } do |f| %>
<div class="filter_form_field filter_select">
<%= f.label 'first_name' %>
<%= f.text_field 'first_name', value: @filter_params[:first_name] %>
</div>
<div class="filter_form_field filter_select">
<%= f.label 'last_name' %>
<%= f.text_field 'last_name', value: @filter_params[:last_name] %>
</div>
Javascript doesn't work for me. (Hacky method not called before original click event handler). I've to change JS code by this :
# Extend the clear-filters button to clear saved filters
$(document).on 'ready page:load', ->
original_click = $._data($('.clear_filters_btn')[0], "events").click[0].handler
$('.clear_filters_btn').off('click')
$('.clear_filters_btn').on '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'
}
original_click.apply(this, [evt])
I had issues where I could not clear the filters once set. The clear filter ajax seemed to work, but when the page reloaded the filters were still there. Clearing them manually and then hitting Filter button also failed, as the result was aparams[:q] = nil
.
I ended up modifying restore_search_filters to look at the value of params["commit"]
to decided if I wanted to load params[:q]
.
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
filter_storage.delete controller_key
params[:q] = nil if params["commit"].present? && params["commit"] != "Filter"
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
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!
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
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 / тιηуηυмвєяѕ <[email protected]>
# 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'
});
});
});
Nice extension @tinynumbers.
Just one note. When I applied this to my app, I had to make a small adjustment so that the fix would not get loaded in my devise-powered ActiveAdmin's login page.
Notice the
unless
clause on the filters. Without this, the devise controller was trying to invoke those filters when visiting the login page, but since this controller does not derive fromActiveAdmin::BaseController
, it raised a 'method not found' error.I hope this is useful for anyone else out there in a similar situation ;)