module Datagrid module Filters require "datagrid/filters/base_filter" require "datagrid/filters/enum_filter" require "datagrid/filters/boolean_enum_filter" require "datagrid/filters/boolean_filter" require "datagrid/filters/date_filter" require "datagrid/filters/default_filter" require "datagrid/filters/filter_eval" require "datagrid/filters/integer_filter" require "datagrid/filters/composite_filters" FILTER_TYPES = { :date => Filters::DateFilter, :string => Filters::DefaultFilter, :default => Filters::DefaultFilter, :eboolean => Filters::BooleanEnumFilter , :boolean => Filters::BooleanFilter , :integer => Filters::IntegerFilter, :enum => Filters::EnumFilter, } def self.included(base) base.extend ClassMethods base.class_eval do include Datagrid::Core include Datagrid::Filters::CompositeFilters end base.send :include, InstanceMethods end # self.included module ClassMethods def filters @filters ||= [] end def filter_by_name(attribute) self.filters.find do |filter| filter.name.to_sym == attribute.to_sym end end # Defines the accessible attribute that is used to filter # scope by the specified value with specified code. # # Example: # # class UserGrid # include Datagrid # # filter(:name) # filter(:posts_count, :integer) do |value| # self.where(["posts_count >= ?", value]) # end # # scope do # User.order("users.created_at desc") # end # end # # Each filter becomes grid atttribute. # In order to create grid that display all users with name 'John' that have more than zero posts: # # grid = UserGrid.new(:posts_count => 1, :name => "John") # grid.assets # SELECT * FROM users WHERE users.posts_count > 1 AND name = 'John' # # Important! Take care about non-breaking the filter chain and force objects loading in filter. # The filter block should always return a ActiveRecord::Scope rather than Array # # = Default filter block # # If no block given filter is generated automatically as simple select by filter name from scope. # # = Filter types # # Filter does types conversion automatically. # The following filter types are supported: # # * :string (default) - converts value to string # * :date - converts value to date using date parser # * :enum - designed to be collection select. Additional options for easy form generation: # * :select (required) - collection of values to match agains. # * :multiple - if true multiple values can be assigned to this filter. Default: false. # * :eboolean - subtype of enum filter that provides select of "Yes", "No" and "Any". Could be useful. # * :integer - converts given value to integer. # # def filter(attribute, type = :string, options = {}, &block) klass = type.is_a?(Class) ? type : FILTER_TYPES[type] raise ConfigurationError, "filter class not found" unless klass block ||= default_filter(attribute) filter = klass.new(self, attribute, options, &block) self.filters << filter datagrid_attribute(attribute) do |value| filter.format(value) end end protected def default_filter(attribute) if self.scope.column_names.include?(attribute.to_s) lambda do |value| self.scoped(:conditions => {attribute => value}) end else raise ConfigurationError, "Not able to generate default filter. No column '#{attribute}' in #{self.scope.table_name}." end end end # ClassMethods module InstanceMethods def initialize(*args, &block) self.filters.each do |filter| self[filter.name] = filter.default end super(*args, &block) end def assets result = super self.class.filters.each do |filter| result = filter.apply(result, filter_value(filter)) end result end def filters self.class.filters end def filter_value(filter) self[filter.name] end end # InstanceMethods end end