Module: Filtered::Base::ClassMethods

Included in:
Filtered::Base
Defined in:
lib/filtered/base.rb

Instance Method Summary collapse

Instance Method Details

#field(field_name, options = {}, &block) ⇒ Object

Defines a field in a filter.

When you provide no options, it will by default add a simple ‘where(year: [“2010”, “2011”])` clause to the query.

class CarFilter < ApplicationFilter

  field :year

end

Or with a block which is passed with the current field value. Note that block must return proc which will be merged in the query:

class CarFilter < ApplicationFilter

  field :year do |value|
    -> { where(year: "20#{value}") }
  end

end

The second argument to a block is filter object itself:

class CarFilter < ApplicationFilter

  attr_accessor :user

  field :year, allow_blank: true do |value, filter|
    -> { where(year: value, user: filter.user) }
  end

end

Options:

  • :default - Specifies a method (e.g. default: :default_year), proc (e.g. default: Proc.new { |filter| filter.default_year }) or object (e.g default: "2012") to call to determine default value. It will be called only if the field not passed into filter constructor.

  • :allow_nil - Add the field into query if field value is nil.

  • :allow_blank - Add the field into query if the value is blank.

  • :if - Specifies a method or proc to call to determine if the field addition to query should occur (e.g. if: :allow_year, or if: Proc.new { |year| %w(2018 2019).include?(year) }). The method, or proc should return a true or false value.

  • :unless - Specifies a method or proc to call to determine if the field addition to query should not occur (e.g. if: :allow_year, or if: Proc.new { |year| (1999..2005).include?(year) }). The method, or proc should return a true or false value.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/filtered/base.rb', line 55

def field(field_name, options = {}, &block)
  field_name = field_name.to_sym

  field_definition = FieldDefinition.new.tap do |fd|
    fd.query_updater = if block_given?
      # TODO look for methods to validate that block returns proc
      block
    else
      # AR ref
      ->(value) { -> { where(field_name => value) } }
    end


    raise Error, "'if' can't be used with 'allow_nil' or 'allow_blank'" if options[:if] && (options[:allow_nil] || options[:allow_blank])

    fd.acceptance_computer = if options[:if].is_a?(Proc)
      options[:if]
    elsif options[:if].is_a?(Symbol)
      -> (value, filter) { filter.send(options[:if], value) }
    elsif options[:if].nil?
      # TODO checking that value is blank just comparing to empty string is very naive
      ->(value) { (options[:allow_nil] || !value.nil?) && (options[:allow_blank] || value != "") }
    else
      raise Error, "Unsupported argument #{options[:if].class} for 'if'. Pass proc or method name"
    end


    raise Error, "'unless' can't be used with 'allow_nil' or 'allow_blank'" if options[:unless] && (options[:allow_nil] || options[:allow_blank])

    fd.decline_computer = if options[:unless].is_a?(Proc)
      options[:unless]
    elsif options[:unless].is_a?(Symbol)
      -> (value, filter) { filter.send(options[:unless], value) }
    elsif options[:unless].nil?
      -> { false }
    else
      raise Error, "Unsupported argument #{options[:unless].class} for 'unless'. Pass proc or method name"
    end


    fd.default_computer = if options[:default].is_a?(Proc)
      options[:default]
    elsif options[:default].is_a?(Symbol)
      -> (filter) { filter.send(options[:default]) }
    elsif options[:default]
      -> (_) { options[:default] }
    end
  end

  field_definitions[field_name] = field_definition

  define_method field_name do
    fields[field_name]
  end
end

#field_definitionsObject



111
112
113
# File 'lib/filtered/base.rb', line 111

def field_definitions
  instance_variable_get(:"@field_definitions")
end