Class: WillFilter::Filter

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/will_filter/filter.rb

Constant Summary collapse

JOIN_NAME_INDICATOR =
'>'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model_class = nil) ⇒ Filter

Basics



66
67
68
69
70
71
72
73
74
# File 'app/models/will_filter/filter.rb', line 66

def initialize(model_class = nil)
  super()

  if WillFilter::Config.require_filter_extensions? and self.class.name == 'WillFilter::Filter'
    raise WillFilter::FilterException.new('Your configuration requires you to subclass the filter. Default filter cannot be created.')
  end

  self.model_class_name = model_class.to_s
end

Class Method Details

.container_by_sql_type(type) ⇒ Object



207
208
209
210
# File 'app/models/will_filter/filter.rb', line 207

def self.container_by_sql_type(type)
  raise WillFilter::FilterException.new("Unsupported data type #{type}") unless WillFilter::Config.data_types[type]
  WillFilter::Config.data_types[type]
end

.deserialize_from_params(params) ⇒ Object

allows to create a filter from params only



536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
# File 'app/models/will_filter/filter.rb', line 536

def self.deserialize_from_params(params)
  params = HashWithIndifferentAccess.new(params) unless params.is_a?(HashWithIndifferentAccess)

  params[:wf_type] = self.name unless params[:wf_type]
  filter_class = params[:wf_type].constantize
  filter_instance = filter_class.new

  unless filter_instance.kind_of?(WillFilter::Filter)
    raise WillFilter::FilterException.new("Invalid filter class. Filter classes must extand WillFilter::Filter.")
  end

  if WillFilter::Config.require_filter_extensions?
    filter_instance.deserialize_from_params(params)
  else
    filter_class.new(params[:wf_model]).deserialize_from_params(params)
  end
end

Instance Method Details

#add_condition(condition_key, operator_key, values = []) ⇒ Object



407
408
409
# File 'app/models/will_filter/filter.rb', line 407

def add_condition(condition_key, operator_key, values = [])
  add_condition_at(size, condition_key, operator_key, values)
end

#add_condition!(condition_key, operator_key, values = []) ⇒ Object



411
412
413
414
# File 'app/models/will_filter/filter.rb', line 411

def add_condition!(condition_key, operator_key, values = [])
  add_condition(condition_key, operator_key, values)
  self
end

#add_condition_at(index, condition_key, operator_key, values = []) ⇒ Object



432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'app/models/will_filter/filter.rb', line 432

def add_condition_at(index, condition_key, operator_key, values = [])
  values = [values] unless values.instance_of?(Array)
  values = values.collect{|v| v.to_s}

  condition_key = condition_key.to_sym if condition_key.is_a?(String)

  unless valid_operator?(condition_key, operator_key)
    opers = definition[condition_key]
    operator_key = first_sorted_operator(opers)
  end

  condition = WillFilter::FilterCondition.new(self, condition_key, operator_key, container_for(condition_key, operator_key), values)
  @conditions.insert(index, condition)
end

#add_default_condition_at(index) ⇒ Object



484
485
486
# File 'app/models/will_filter/filter.rb', line 484

def add_default_condition_at(index)
  add_condition_at(index, default_condition_key, default_operator_key(default_condition_key))
end

#association_class(inner_join) ⇒ Object



866
867
868
# File 'app/models/will_filter/filter.rb', line 866

def association_class(inner_join)
  model_class.new.association(association_name(inner_join)).build.class
end

#association_name(inner_join) ⇒ Object



862
863
864
# File 'app/models/will_filter/filter.rb', line 862

def association_name(inner_join)
  (inner_join.is_a?(Array) ? inner_join.first : inner_join).to_sym
end

#avg(column_name) ⇒ Object



963
964
965
# File 'app/models/will_filter/filter.rb', line 963

def avg(column_name)
  model_class.average(column_name, :conditions => sql_conditions)
end

#clone_with_condition(condition_key, operator_key, values = []) ⇒ Object



416
417
418
# File 'app/models/will_filter/filter.rb', line 416

def clone_with_condition(condition_key, operator_key, values = [])
  dup.add_condition!(condition_key, operator_key, values)
end

#column_sorted?(key) ⇒ Boolean

Returns:

  • (Boolean)


295
296
297
# File 'app/models/will_filter/filter.rb', line 295

def column_sorted?(key)
  key.to_s == order
end

#condition_at(index) ⇒ Object



469
470
471
# File 'app/models/will_filter/filter.rb', line 469

def condition_at(index)
  conditions[index]
end

#condition_by_key(key) ⇒ Object



473
474
475
476
477
478
# File 'app/models/will_filter/filter.rb', line 473

def condition_by_key(key)
  conditions.each do |c|
    return c if c.key==key
  end
  nil
end

#condition_optionsObject



349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'app/models/will_filter/filter.rb', line 349

def condition_options
  @condition_options ||= begin
    opts = []
    definition.keys.each do |cond|
      opts << [condition_title_for(cond), cond.to_s]
    end
    opts = opts.sort_by{|opt| opt.first.gsub(JOIN_NAME_INDICATOR, 'zzz') }

    separated = []
    opts.each_with_index do |opt, index|
      if index > 0
        prev_opt_parts = opts[index-1].first.split(":")
        curr_opt_parts = opt.first.split(":")

        if (prev_opt_parts.size != curr_opt_parts.size) or (curr_opt_parts.size > 1 and (prev_opt_parts.first != curr_opt_parts.first))
          key_parts = opt.last.split('.')
          separated << ["-------------- #{curr_opt_parts.first.gsub("#{JOIN_NAME_INDICATOR} ", '')} --------------", "#{key_parts.first}.id"]
        end
      end
      separated << opt
    end
    separated
  end
end

#condition_title_for(key) ⇒ Object

Can be overloaded for custom titles



338
339
340
341
342
343
344
345
346
347
# File 'app/models/will_filter/filter.rb', line 338

def condition_title_for(key)
  title_parts = key.to_s.split('.')
  title = key.to_s.gsub(".", ": ").gsub("_", " ")
  title = title.split(" ").collect{|part| part.split("/").last.capitalize}.join(" ")
  if title_parts.size > 1
    "#{JOIN_NAME_INDICATOR} #{title}"
  else
    title
  end
end

#conditionsObject



465
466
467
# File 'app/models/will_filter/filter.rb', line 465

def conditions
  @conditions ||= []
end

#conditions=(new_conditions) ⇒ Object



461
462
463
# File 'app/models/will_filter/filter.rb', line 461

def conditions=(new_conditions)
  @conditions = new_conditions
end

#conditions_for(condition_key) ⇒ Object



399
400
401
# File 'app/models/will_filter/filter.rb', line 399

def conditions_for(condition_key)
  @conditions.select{|cond| cond.key == condition_key}
end

#container_by_sql_type(type) ⇒ Object



212
213
214
# File 'app/models/will_filter/filter.rb', line 212

def container_by_sql_type(type)
  self.class.container_by_sql_type(type)
end

#container_for(condition_key, operator_key) ⇒ Object



387
388
389
390
391
392
393
394
395
396
397
# File 'app/models/will_filter/filter.rb', line 387

def container_for(condition_key, operator_key)
  condition_key = condition_key.to_sym if condition_key.is_a?(String)

  opers = definition[condition_key]
  raise WillFilter::FilterException.new("Invalid condition #{condition_key} for filter #{self.class.name}") unless opers
  oper = opers[operator_key]

  # if invalid operator_key was passed, use first operator
  oper = opers[first_sorted_operator(opers)] unless oper
  oper
end

#contains_column?(key) ⇒ Boolean

Returns:

  • (Boolean)


174
175
176
# File 'app/models/will_filter/filter.rb', line 174

def contains_column?(key)
  model_column_keys.index(key.to_sym) != nil
end

#count(column_name) ⇒ Object



967
968
969
# File 'app/models/will_filter/filter.rb', line 967

def count(column_name)
  model_class.count(column_name, :conditions => sql_conditions)
end

#custom_condition?(condition) ⇒ Boolean

Returns:

  • (Boolean)


890
891
892
# File 'app/models/will_filter/filter.rb', line 890

def custom_condition?(condition)
  custom_conditions.include?(condition.key)
end

#custom_condition_met?(condition, object) ⇒ Boolean

overload this method to evaluate a custom condition on an object

Returns:

  • (Boolean)


886
887
888
# File 'app/models/will_filter/filter.rb', line 886

def custom_condition_met?(condition, object)
  false
end

#custom_conditionsObject

overload this method to indicate which conditions are custom



881
882
883
# File 'app/models/will_filter/filter.rb', line 881

def custom_conditions
  []
end

#custom_conditions?Boolean

Returns:

  • (Boolean)


894
895
896
897
898
899
# File 'app/models/will_filter/filter.rb', line 894

def custom_conditions?
  return if custom_conditions.empty?
  conditions.each do |condition|
    return true if custom_condition?(condition)
  end
end

#custom_format?Boolean

Returns:

  • (Boolean)


847
848
849
850
851
852
# File 'app/models/will_filter/filter.rb', line 847

def custom_format?
  custom_formats.each do |frmt|
    return true if frmt[1].to_sym == format
  end
  false
end

#custom_formatsObject



854
855
856
# File 'app/models/will_filter/filter.rb', line 854

def custom_formats
  []
end

#debug_conditions(conds) ⇒ Object



697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
# File 'app/models/will_filter/filter.rb', line 697

def debug_conditions(conds)
  all_conditions = []
  conds.each_with_index do |c, i|
    cond = ""
    if i == 0
      cond << "\"<b>#{c}</b>\""
    else
      cond << "<br>&nbsp;&nbsp;&nbsp;<b>#{i})</b>&nbsp;"
      if c.is_a?(Array)
        cond << "["
        cond << (c.collect{|v| "\"#{v.strip}\""}.join(", "))
        cond << "]"
      elsif c.is_a?(Date)
        cond << "\"#{c.strftime("%Y-%m-%d")}\""
      elsif c.is_a?(Time)
        cond << "\"#{c.strftime("%Y-%m-%d %H:%M:%S")}\""
      elsif c.is_a?(Integer)
        cond << c.to_s
      else
        cond << "\"#{c}\""
      end
    end

    all_conditions << cond
  end
  all_conditions.join("")
end

#debug_sql_conditionsObject



725
726
727
# File 'app/models/will_filter/filter.rb', line 725

def debug_sql_conditions
  debug_conditions(sql_conditions)
end

#default_condition_definition_for(name, sql_data_type) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'app/models/will_filter/filter.rb', line 216

def default_condition_definition_for(name, sql_data_type)
  type = sql_data_type.split(" ").first.split("(").first.downcase
  containers = container_by_sql_type(type)
  operators = {}
  containers.each do |c|
    raise WillFilter::FilterException.new("Unsupported container implementation for #{c}") unless WillFilter::Config.containers[c]
    container_klass = WillFilter::Config.containers[c].constantize
    container_klass.operators.each do |o|
      operators[o] = c
    end
  end

  if name == "id"
    operators[:is_filtered_by] = :filter_list
  elsif "_id" == name[-3..-1]
    begin
      name[0..-4].camelcase.constantize
      operators[:is_filtered_by] = :filter_list
    rescue
    end
  end

  operators
end

#default_condition_keyObject

options always go in [NAME, KEY] format



450
451
452
# File 'app/models/will_filter/filter.rb', line 450

def default_condition_key
  condition_options.first.last
end

#default_filter_conditions(key) ⇒ Object



793
794
795
# File 'app/models/will_filter/filter.rb', line 793

def default_filter_conditions(key)
  []
end

#default_filter_if_emptyObject

overload this method if you don’t want to allow empty filters



779
780
781
# File 'app/models/will_filter/filter.rb', line 779

def default_filter_if_empty
  nil
end

#default_filtersObject



789
790
791
# File 'app/models/will_filter/filter.rb', line 789

def default_filters
  []
end

#default_operator_key(condition_key) ⇒ Object

options always go in [NAME, KEY] format



457
458
459
# File 'app/models/will_filter/filter.rb', line 457

def default_operator_key(condition_key)
  operator_options_for(condition_key).first.last
end

#default_orderObject



253
254
255
# File 'app/models/will_filter/filter.rb', line 253

def default_order
  'id'
end

#default_order_typeObject



263
264
265
# File 'app/models/will_filter/filter.rb', line 263

def default_order_type
  'desc'
end

#default_per_pageObject



299
300
301
# File 'app/models/will_filter/filter.rb', line 299

def default_per_page
  100
end

#default_per_page_optionsObject



311
312
313
# File 'app/models/will_filter/filter.rb', line 311

def default_per_page_options
  [10, 20, 30, 40, 50, 100, 500, 1000]
end

#definitionObject



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'app/models/will_filter/filter.rb', line 178

def definition
  @definition ||= begin
    defs = {}
    model_columns.each do |col|
      key = col.name.to_sym
      next unless contains_column?(key)
      defs[key] = default_condition_definition_for(col.name, col.sql_type)
    end
    inner_joins.each do |inner_join|
      join_class = association_class(inner_join)
      join_class.columns.each do |col|
        defs[:"#{join_class.to_s.underscore}.#{col.name.to_sym}"] = default_condition_definition_for(col.name, col.sql_type)
      end
    end

    defs
  end
end

#deserialize_from_params(params) ⇒ Object Also known as: from_params



554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
# File 'app/models/will_filter/filter.rb', line 554

def deserialize_from_params(params)
  params = HashWithIndifferentAccess.new(params) unless params.is_a?(HashWithIndifferentAccess)

  @conditions = []
  @match                = params[:wf_match]       || :all
  @key                  = params[:wf_key]         || self.id.to_s

  self.model_class_name = params[:wf_model]       if params[:wf_model]

  @per_page             = params[:wf_per_page]    || default_per_page
  @page                 = params[:page]           || 1
  @order_type           = params[:wf_order_type]  || default_order_type
  @order                = params[:wf_order]       || default_order

  self.id   =  params[:wf_id].to_i  unless params[:wf_id].blank?
  self.name =  params[:wf_name]     unless params[:wf_name].blank?

  @fields = []
  unless params[:wf_export_fields].blank?
    params[:wf_export_fields].split(",").each do |fld|
      @fields << fld.to_sym
    end
  end

  if params[:wf_export_format].blank?
    @format = :html
  else
    @format = params[:wf_export_format].to_sym
  end

  i = 0
  while params["wf_c#{i}"] do
    conditon_key = params["wf_c#{i}"]
    operator_key = params["wf_o#{i}"]
    values = []
    j = 0
    while params["wf_v#{i}_#{j}"] do
      values << params["wf_v#{i}_#{j}"]
      j += 1
    end
    i += 1
    add_condition(conditon_key, operator_key.to_sym, values)
  end

  if params[:wf_submitted] == 'true'
    validate!
  end

  if WillFilter::Config.user_filters_enabled? and WillFilter::Config.current_user
    self.user_id = WillFilter::Config.current_user.id
  end

  if WillFilter::Config.project_filters_enabled? and WillFilter::Config.current_project
    self.project_id = WillFilter::Config.current_project.id
  end

  self
end

#dupObject



76
77
78
# File 'app/models/will_filter/filter.rb', line 76

def dup
  super.tap {|ii| ii.conditions = self.conditions.dup}
end

#empty?Boolean

Returns:

  • (Boolean)


621
622
623
# File 'app/models/will_filter/filter.rb', line 621

def empty?
  size == 0
end

#errorsObject



109
110
111
# File 'app/models/will_filter/filter.rb', line 109

def errors
  @errors ||= {}
end

#errors?Boolean

Validations

Returns:

  • (Boolean)


617
618
619
# File 'app/models/will_filter/filter.rb', line 617

def errors?
  (@errors and @errors.size > 0)
end

#export_formatsObject

Export Filter Data



832
833
834
835
836
837
838
839
840
841
842
843
844
845
# File 'app/models/will_filter/filter.rb', line 832

def export_formats
  formats = []
  formats << ["-- Generic Formats --", -1]
  WillFilter::Config.default_export_formats.each do |frmt|
    formats << [frmt, frmt]
  end
  if custom_formats.size > 0
    formats << ["-- Custom Formats --", -2]
    custom_formats.each do |frmt|
      formats << frmt
    end
  end
  formats
end

#extra_paramsObject



121
122
123
# File 'app/models/will_filter/filter.rb', line 121

def extra_params
  @extra_params ||= {}
end

#fieldsObject



117
118
119
# File 'app/models/will_filter/filter.rb', line 117

def fields
  @fields ||= []
end

#filter_optionsObject



758
759
760
761
762
763
764
765
766
767
768
769
770
# File 'app/models/will_filter/filter.rb', line 758

def filter_options
  filters = [['', [['', '']]]]

  if default_filters.any?
    filters << ['Pre-defined Filters', default_filters]
  end

  if saved_filters.any?
    filters << ['Saved Filters', saved_filters]
  end

  filters
end

#first_sorted_operator(opers) ⇒ Object



249
250
251
# File 'app/models/will_filter/filter.rb', line 249

def first_sorted_operator(opers)
  sorted_operators(opers).first.to_sym
end

#formatObject



113
114
115
# File 'app/models/will_filter/filter.rb', line 113

def format
  @format ||= :html
end

#handle_empty_filter!Object



783
784
785
786
787
# File 'app/models/will_filter/filter.rb', line 783

def handle_empty_filter!
  return unless empty?
  return if default_filter_if_empty.nil?
  load_filter!(default_filter_if_empty)
end

#has_condition?(key) ⇒ Boolean

Returns:

  • (Boolean)


625
626
627
# File 'app/models/will_filter/filter.rb', line 625

def has_condition?(key)
  condition_by_key(key) != nil
end

#inner_joinsObject

Inner Joins come in a form of

[joining_model_name, column_name], [joining_model_name, column_name]


162
163
164
# File 'app/models/will_filter/filter.rb', line 162

def inner_joins
  []
end

#joinsObject

deprecated for Rails 3.0 and up



871
872
873
874
875
876
877
878
# File 'app/models/will_filter/filter.rb', line 871

def joins
  return nil if inner_joins.empty?
  inner_joins.collect do |inner_join|
    join_table_name = association_class(inner_join).table_name
    join_on_field = inner_join.last.to_s
    "INNER JOIN #{join_table_name} ON #{join_table_name}.id = #{table_name}.#{join_on_field}"
  end
end

#keyObject



105
106
107
# File 'app/models/will_filter/filter.rb', line 105

def key
  @key ||= ''
end

#key=(new_key) ⇒ Object



150
151
152
# File 'app/models/will_filter/filter.rb', line 150

def key=(new_key)
  @key = new_key
end

#load_default_filter(key) ⇒ Object



797
798
799
800
801
802
803
804
805
806
807
808
809
# File 'app/models/will_filter/filter.rb', line 797

def load_default_filter(key)
  default_conditions = default_filter_conditions(key)
  return if default_conditions.nil? or default_conditions.empty?

  unless default_conditions.first.is_a?(Array)
    add_condition(*default_conditions)
    return
  end

  default_conditions.each do |default_condition|
    add_condition(*default_condition)
  end
end

#load_filter!(key_or_id) ⇒ Object



817
818
819
820
821
822
823
824
825
826
827
# File 'app/models/will_filter/filter.rb', line 817

def load_filter!(key_or_id)
  reset!
  @key = key_or_id.to_s

  load_default_filter(key)
  return self unless empty?

  filter = WillFilter::Filter.find_by_id(key_or_id.to_i)
  raise WillFilter::FilterException.new("Invalid filter key #{key_or_id.to_s}") if filter.nil?
  filter
end

#matchObject



101
102
103
# File 'app/models/will_filter/filter.rb', line 101

def match
  @match ||= :all
end

#match=(new_match) ⇒ Object



154
155
156
# File 'app/models/will_filter/filter.rb', line 154

def match=(new_match)
  @match = new_match
end

#match_optionsObject



323
324
325
# File 'app/models/will_filter/filter.rb', line 323

def match_options
  [["all", "all"], ["any", "any"]]
end

#max(column_name) ⇒ Object



955
956
957
# File 'app/models/will_filter/filter.rb', line 955

def max(column_name)
  model_class.maximum(column_name, :conditions => sql_conditions)
end

#min(column_name) ⇒ Object



959
960
961
# File 'app/models/will_filter/filter.rb', line 959

def min(column_name)
  model_class.minimum(column_name, :conditions => sql_conditions)
end

#model_classObject

For extra security, this method must be overloaded by the extending class.



134
135
136
137
138
139
140
141
142
143
144
# File 'app/models/will_filter/filter.rb', line 134

def model_class
  if WillFilter::Config.require_filter_extensions?
    raise WillFilter::FilterException.new("model_class method must be overloaded in the extending class.")
  end

  if model_class_name.blank?
    raise WillFilter::FilterException.new("model_class_name was not specified.")
  end

  @model_class ||= model_class_name.constantize
end

#model_class_for_column_key(key) ⇒ Object



241
242
243
# File 'app/models/will_filter/filter.rb', line 241

def model_class_for_column_key(key)
  nil
end

#model_column_keysObject



170
171
172
# File 'app/models/will_filter/filter.rb', line 170

def model_column_keys
  @model_column_keys ||= model_columns.collect{|col| col.name.to_sym}
end

#model_columnsObject



166
167
168
# File 'app/models/will_filter/filter.rb', line 166

def model_columns
  @model_columns ||= model_class.columns
end

#operator_options_for(condition_key) ⇒ Object



374
375
376
377
378
379
380
# File 'app/models/will_filter/filter.rb', line 374

def operator_options_for(condition_key)
  condition_key = condition_key.to_sym if condition_key.is_a?(String)

  opers = definition[condition_key]
  raise WillFilter::FilterException.new("Invalid condition #{condition_key} for filter #{self.class.name}") unless opers
  sorted_operators(opers).collect{|o| [o.to_s.gsub('_', ' '), o]}
end

#orderObject



257
258
259
260
261
# File 'app/models/will_filter/filter.rb', line 257

def order
  @order ||= default_order
  @order = default_order unless contains_column?(@order.to_sym)
  @order
end

#order_clauseObject



284
285
286
287
288
289
290
291
292
293
# File 'app/models/will_filter/filter.rb', line 284

def order_clause
  @order_clause ||= begin
    order_parts = order.split('.')
    if order_parts.size > 1
      "#{order_parts.first.camelcase.constantize.table_name}.#{order_parts.last} #{order_type}"
    else
      "#{model_class_name.constantize.table_name}.#{order_parts.first} #{order_type}"
    end
  end
end

#order_configurable?Boolean

Returns:

  • (Boolean)


327
328
329
# File 'app/models/will_filter/filter.rb', line 327

def order_configurable?
  true
end

#order_modelObject



273
274
275
276
277
278
279
280
281
282
# File 'app/models/will_filter/filter.rb', line 273

def order_model
  @order_model ||= begin
    order_parts = order.split('.')
    if order_parts.size > 1
      order_parts.first.camelcase
    else
      model_class_name
    end
  end
end

#order_typeObject



267
268
269
270
271
# File 'app/models/will_filter/filter.rb', line 267

def order_type
  @order_type ||= default_order_type
  @order_type = default_order_type unless ['asc', 'desc'].include?(@order_type.to_s)
  @order_type
end

#order_type_optionsObject



331
332
333
# File 'app/models/will_filter/filter.rb', line 331

def order_type_options
  [["desc", "desc"], ["asc", "asc"]]
end

#pageObject



307
308
309
# File 'app/models/will_filter/filter.rb', line 307

def page
  @page ||= 1
end

#per_pageObject



303
304
305
# File 'app/models/will_filter/filter.rb', line 303

def per_page
  @per_page ||= default_per_page
end

#per_page_configurable?Boolean

Returns:

  • (Boolean)


315
316
317
# File 'app/models/will_filter/filter.rb', line 315

def per_page_configurable?
  true
end

#per_page_optionsObject



319
320
321
# File 'app/models/will_filter/filter.rb', line 319

def per_page_options
  @per_page_options ||= default_per_page_options.collect{ |n| [n.to_s, n.to_s] }
end

#prepare_saveObject



80
81
82
83
# File 'app/models/will_filter/filter.rb', line 80

def prepare_save
  self.data = serialize_to_params
  self.type = self.class.name
end

#process_custom_conditions(objects) ⇒ Object



901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
# File 'app/models/will_filter/filter.rb', line 901

def process_custom_conditions(objects)
  filtered = []
  objects.each do |obj|
    condition_flags = []

    0.upto(size - 1) do |index|
      condition = condition_at(index)
      next unless custom_condition?(condition)
      condition_flags << custom_condition_met?(condition, obj)
    end

    if condition_flags.size > 0
      next if match.to_s == "all" and condition_flags.include?(false)
      next unless condition_flags.include?(true)
    end

    filtered << obj
  end
  filtered
end

#process_custom_formatObject



858
859
860
# File 'app/models/will_filter/filter.rb', line 858

def process_custom_format
  ""
end

#process_findObject



85
86
87
88
# File 'app/models/will_filter/filter.rb', line 85

def process_find
  @errors = {}
  deserialize_from_params(self.data)
end

#remove_allObject



492
493
494
# File 'app/models/will_filter/filter.rb', line 492

def remove_all
  @conditions = []
end

#remove_condition(condition_key) ⇒ Object



403
404
405
# File 'app/models/will_filter/filter.rb', line 403

def remove_condition(condition_key)
  @conditions -= conditions_for(condition_key)
end

#remove_condition_at(index) ⇒ Object



488
489
490
# File 'app/models/will_filter/filter.rb', line 488

def remove_condition_at(index)
  conditions.delete_at(index)
end

#replace_condition(condition_key, operator_key, values = []) ⇒ Object



420
421
422
423
# File 'app/models/will_filter/filter.rb', line 420

def replace_condition(condition_key, operator_key, values = [])
  remove_condition(condition_key)
  add_condition_at(size, condition_key, operator_key, values)
end

#required_condition_keysObject

a list of indexed fields where at least one of them has to be in a query otherwise the filter may hang the database



129
130
131
# File 'app/models/will_filter/filter.rb', line 129

def required_condition_keys
  []
end

#required_conditions_met?Boolean

Returns:

  • (Boolean)


633
634
635
636
637
638
# File 'app/models/will_filter/filter.rb', line 633

def required_conditions_met?
  return true if required_condition_keys.blank?
  sconditions = conditions.collect{|c| c.key.to_s}
  rconditions = required_condition_keys.collect{|c| c.to_s}
  not (sconditions & rconditions).empty?
end

#reset!Object



811
812
813
814
815
# File 'app/models/will_filter/filter.rb', line 811

def reset!
  remove_all
  @sql_conditions = nil
  @results = nil
end

#resultsObject



922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
# File 'app/models/will_filter/filter.rb', line 922

def results
  @results ||= begin
    handle_empty_filter!

    if sql_conditions and !sql_conditions[0].blank?
      recs = model_class.where(sql_conditions).order(order_clause)
    else
      recs = model_class.order(order_clause)
    end

    inner_joins.each do |inner_join|
      recs = recs.joins(association_name(inner_join))
    end

    if custom_conditions?
      recs = process_custom_conditions(recs.all)
      recs = Kaminari.paginate_array(recs)
    end


    recs = recs.page(page).per(per_page)

    recs.wf_filter = self

    recs
  end
end

#saved_filters(include_default = true) ⇒ Object



772
773
774
# File 'app/models/will_filter/filter.rb', line 772

def saved_filters(include_default = true)
  @saved_filters ||= user_filters.collect{|f| [f.name, f.id.to_s]}
end

#serialize_to_params(merge_params = {}) ⇒ Object Also known as: to_params

Serialization



499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
# File 'app/models/will_filter/filter.rb', line 499

def serialize_to_params(merge_params = {})
  params = {}
  params[:wf_type]          = self.class.name
  params[:wf_match]         = match
  params[:wf_model]         = model_class_name
  params[:wf_order]         = order
  params[:wf_order_type]    = order_type
  params[:wf_per_page]      = per_page
  params[:wf_export_fields] = fields.join(',')
  params[:wf_export_format] = format

  0.upto(size - 1) do |index|
    condition = condition_at(index)
    condition.serialize_to_params(params, index)
  end

  params.merge!(extra_params)
  params.merge!(merge_params)
  HashWithIndifferentAccess.new(params)
end

#show_export_options?Boolean

Defaults

Returns:

  • (Boolean)


93
94
95
# File 'app/models/will_filter/filter.rb', line 93

def show_export_options?
  WillFilter::Config.exporting_enabled?
end

#show_save_options?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'app/models/will_filter/filter.rb', line 97

def show_save_options?
  WillFilter::Config.saving_enabled?
end

#sizeObject



480
481
482
# File 'app/models/will_filter/filter.rb', line 480

def size
  conditions.size
end

#sorted_operators(opers) ⇒ Object



245
246
247
# File 'app/models/will_filter/filter.rb', line 245

def sorted_operators(opers)
  (WillFilter::Config.operator_order & opers.keys.collect{|o| o.to_s})
end

#sql_attribute_for_key(key) ⇒ Object



197
198
199
200
201
202
203
204
205
# File 'app/models/will_filter/filter.rb', line 197

def sql_attribute_for_key(key)
  if key.to_s.index('.')
    parts = key.to_s.split('.')
    join_class = parts.first.camelcase.constantize
    "#{join_class.table_name}.#{parts.last}"
  else
    "#{table_name}.#{key}"
  end
end

#sql_conditionsObject



663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
# File 'app/models/will_filter/filter.rb', line 663

def sql_conditions
  @sql_conditions ||= begin
    if errors?
      [' 1 = 2 ']
    else
      all_sql_conditions = ['']
      0.upto(size - 1) do |index|
        condition = condition_at(index)
        next if custom_condition?(condition)
        next unless condition.container

        sql_condition = to_sql_condition(condition)

        unless sql_condition
          raise WillFilter::FilterException.new("Unsupported operator #{condition.operator_key} for container #{condition.container.class.name}")
        end

        if all_sql_conditions[0].size > 0
          all_sql_conditions[0] << ( match.to_sym == :all ? ' AND ' : ' OR ')
        end

        all_sql_conditions[0] << sql_condition[0]

        sql_condition[1..-1].each do |c|
          all_sql_conditions << c
        end

      end

      all_sql_conditions
    end
  end
end

#sum(column_name) ⇒ Object

sums up the column for the given conditions



951
952
953
# File 'app/models/will_filter/filter.rb', line 951

def sum(column_name)
  model_class.sum(column_name, :conditions => sql_conditions)
end

#table_nameObject



146
147
148
# File 'app/models/will_filter/filter.rb', line 146

def table_name
  model_class.table_name
end

#to_sObject



529
530
531
# File 'app/models/will_filter/filter.rb', line 529

def to_s
  to_url_params
end

#to_sql_condition(condition) ⇒ Object

SQL Conditions



659
660
661
# File 'app/models/will_filter/filter.rb', line 659

def to_sql_condition(condition)
  condition.container.sql_condition
end

#to_url_paramsObject



521
522
523
524
525
526
527
# File 'app/models/will_filter/filter.rb', line 521

def to_url_params
  params = []
  serialize_to_params.each do |name, value|
    params << "#{name.to_s}=#{ERB::Util.url_encode(value)}"
  end
  params.join("&")
end

#user_filtersObject

Saved Filters



732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
# File 'app/models/will_filter/filter.rb', line 732

def user_filters
  @user_filters ||= begin
    conditions = ['model_class_name = ?', self.model_class_name]

    if WillFilter::Config.user_filters_enabled?
      conditions[0] << ' and user_id = ? '
      if WillFilter::Config.current_user and WillFilter::Config.current_user.id
        conditions << WillFilter::Config.current_user.id
      else
        conditions << '0'
      end
    end

    if WillFilter::Config.project_filters_enabled?
      conditions[0] << ' and project_id = ? '
      if WillFilter::Config.current_project and WillFilter::Config.current_project.id
        conditions << WillFilter::Config.current_project.id
      else
        conditions << '0'
      end
    end

    WillFilter::Filter.where(conditions)
  end
end

#valid_format?Boolean

Returns:

  • (Boolean)


629
630
631
# File 'app/models/will_filter/filter.rb', line 629

def valid_format?
  WillFilter::Config.default_export_formats.include?(format.to_s)
end

#valid_operator?(condition_key, operator_key) ⇒ Boolean

Returns:

  • (Boolean)


425
426
427
428
429
430
# File 'app/models/will_filter/filter.rb', line 425

def valid_operator?(condition_key, operator_key)
  condition_key = condition_key.to_sym if condition_key.is_a?(String)
  opers = definition[condition_key]
  return false unless opers
  opers[operator_key]!=nil
end

#validate!Object



640
641
642
643
644
645
646
647
648
649
650
651
652
653
# File 'app/models/will_filter/filter.rb', line 640

def validate!
  @errors = {}
  0.upto(size - 1) do |index|
    condition = condition_at(index)
    err = condition.validate
    @errors[index] = err if err
  end

  unless required_conditions_met?
    @errors[:filter] = "Filter must contain at least one of the following conditions: #{required_condition_keys.join(", ")}"
  end

  errors?
end

#value_options_for(condition_key) ⇒ Object

called by the list container, should be overloaded in a subclass



383
384
385
# File 'app/models/will_filter/filter.rb', line 383

def value_options_for(condition_key)
  []
end