module RailsStuff::SortScope
Provides safe and flexible way to sort collections by user's input. Uses `has_scope` gem.
Supports different input format, and limits requested fields to allowed subset.
Public Class Methods
extended(base)
click to toggle source
# File lib/rails_stuff/sort_scope.rb, line 63 def extended(base) base.class_eval do include InstanceMethods helper_method :current_sort_scope if respond_to?(:helper_method) end end
filter_param(val, params, allowed, default = nil)
click to toggle source
Filters value with whitelist of allowed fields to sort by.
rubocop:disable CyclomaticComplexity, PerceivedComplexity, BlockNesting
# File lib/rails_stuff/sort_scope.rb, line 73 def filter_param(val, params, allowed, default = nil) val ||= default unless val == default val = val.to_unsafe_h if val.is_a?(ActionController::Parameters) val = if val.is_a?(Hash) val.each_with_object({}) do |(key, dir), h| h[key] = (dir == 'desc' ? :desc : :asc) if allowed.include?(key) end else allowed.include?(val) ? val : default end end if val && !val.is_a?(Hash) val = {val => ParamsParser.parse_boolean(params[:sort_desc]) ? :desc : :asc} end val end
Public Instance Methods
has_sort_scope(config = {})
click to toggle source
Setups has_scope to order collection by allowed columns. Sort column is filtered by SortScope.filter_param
method. Accepts params:
#### Options
-
`by` - array of available fields to sort by,
-
`default` - default sort expression,
-
`only` - bypassed to `has_scope` to limit actions (default to `:index`),
-
`order_method` - use custom method to sort instead of `.order`.
rubocop:disable ClassVars
# File lib/rails_stuff/sort_scope.rb, line 30 def has_sort_scope(config = {}) @@_sort_scope_id ||= 0 default = config[:default] || :id default = default.is_a?(Hash) ? default.stringify_keys : default.to_s allowed = Array.wrap(config[:by]).map(&:to_s) only_actions = config.fetch(:only, :index) order_method = config.fetch(:order_method, :order) # Counter added into scope name to allow to define multiple scopes in same controller. has_scope("sort_#{@@_sort_scope_id += 1}", as: :sort, default: nil, allow_blank: true, only: only_actions, type: :any, ) do |c, scope, val| sort_args = SortScope.filter_param(val, c.params, allowed, default) c.instance_variable_set(:@current_sort_scope, sort_args) scope.public_send(order_method, sort_args) end end