filch 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +7 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +303 -0
  8. data/Rakefile +10 -0
  9. data/app/controllers/filch_controller.rb +13 -0
  10. data/app/views/filch/_associations.html.haml +25 -0
  11. data/app/views/filch/_attributes.html.haml +30 -0
  12. data/app/views/filch/_distinct.html.haml +4 -0
  13. data/app/views/filch/_eq.html.haml +7 -0
  14. data/app/views/filch/_form.html.haml +26 -0
  15. data/app/views/filch/_group.html.haml +4 -0
  16. data/app/views/filch/_gt.html.haml +2 -0
  17. data/app/views/filch/_limit.html.haml +5 -0
  18. data/app/views/filch/_lt.html.haml +2 -0
  19. data/app/views/filch/_null.html.haml +5 -0
  20. data/app/views/filch/_options.html.haml +11 -0
  21. data/app/views/filch/_order.html.haml +4 -0
  22. data/app/views/filch/_pg_group.html.haml +6 -0
  23. data/app/views/filch/_pluck.html.haml +4 -0
  24. data/app/views/filch/_quick.html.haml +3 -0
  25. data/app/views/filch/_scopes.html.haml +11 -0
  26. data/app/views/filch/_search.html.haml +12 -0
  27. data/bin/console +14 -0
  28. data/bin/setup +8 -0
  29. data/config/initializers/assets.rb +1 -0
  30. data/config/initializers/ransack.rb +100 -0
  31. data/config/routes.rb +3 -0
  32. data/filch.gemspec +40 -0
  33. data/lib/filch.rb +375 -0
  34. data/lib/filch/datalist.rb +26 -0
  35. data/lib/filch/engine.rb +5 -0
  36. data/lib/filch/error.rb +4 -0
  37. data/lib/filch/model_find.rb +17 -0
  38. data/lib/filch/ransack_plus.rb +34 -0
  39. data/lib/filch/version.rb +3 -0
  40. data/vendor/assets/javascripts/filch.js +1 -0
  41. data/vendor/assets/javascripts/filchColClick.js +6 -0
  42. data/vendor/assets/javascripts/filchDataList.js +21 -0
  43. data/vendor/assets/javascripts/unhideForm.js +19 -0
  44. metadata +202 -0
@@ -0,0 +1,13 @@
1
+ # The filch controller.
2
+ class FilchController < ::ApplicationController
3
+ # Datalist returns data for the datalist.
4
+ def datalist
5
+ model, column, pq = params[:column].split('.')
6
+ ransack_q = Filch.datalist(model, column, params[pq])
7
+ render(
8
+ partial: 'filch/quick',
9
+ layout: false,
10
+ locals: { q: ransack_q }
11
+ )
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ -template_config.associations_keys.each do |assoc|
2
+ -template_config.associations[assoc].each do |attr, preds|
3
+ -model_name = model.name
4
+ -id = "#{template}_#{model_name}_#{assoc}_#{attr}"
5
+ - datalist_id = "#{id}_datalist"
6
+ -assoc_attrs = {shId: "#{id}_column", datalist: datalist_id, id: id + '_head'}.merge(html_attrs[:assocs])
7
+ %p.js{assoc_attrs}
8
+ ="#{assoc} #{attr}"
9
+ %table{id: "#{id}_column", class: attr}
10
+ %tr
11
+ %td
12
+
13
+ -datalist_attrs = {id: datalist_id, updateInner_addvars: "#{model_name}.#{attr}.#{f.options[:as]}"}.merge(html_attrs[:datalist])
14
+ %datalist{datalist_attrs}
15
+ %option
16
+
17
+ -preds.each do |pred|
18
+ %tr{class: pred}
19
+ -if lookup_context.find_all("filch/_#{pred}").any?
20
+ =render("filch/#{pred}", f: f, datalist_id: datalist_id, attr: "#{assoc}_#{attr}", model: model, html_attrs: html_attrs)
21
+ -else
22
+ %td.label{html_attrs[:label]}=pred
23
+ %td.no_partial
24
+ -field_hash = {list: datalist_id, placeholder:"#{attr} #{pred}"}.merge(html_attrs[:field])
25
+ =f.text_field("#{assoc}_#{attr}_#{pred}", field_hash)
@@ -0,0 +1,30 @@
1
+ -template_config.attributes_keys.each do |attr|
2
+ -model_name = model.name
3
+ -id = "#{template}_#{model_name}_#{attr}"
4
+ -datalist_id = "#{id}_datalist"
5
+ -attrs_attrs = {shId: "#{id}_column", datalist: datalist_id, id: id + '_head'}.merge(html_attrs[:attrs])
6
+ %p.js{attrs_attrs}
7
+ =attr
8
+ %table.js{id: "#{id}_column", class: attr}
9
+ %tr
10
+ %td
11
+ -# TODO: have results from before
12
+ -# load options now?
13
+ -# TODO: why not load all datalists at the same time!
14
+ -datalist_attrs = {id: datalist_id, updateInner_addvars: "#{model_name}.#{attr}.#{f.options[:as]}"}.merge(html_attrs[:datalist])
15
+ %datalist{datalist_attrs}
16
+ %option
17
+
18
+ -template_config.attributes[attr].each do |pred|
19
+ %tr{class: pred}
20
+ -if lookup_context.find_all("filch/_#{attr}_#{pred}").any?
21
+ =render("filch/#{attr}_#{pred}", f: f, datalist_id: datalist_id, attr: attr, pred: pred, model: model, default_value: template_config.default_values["#{attr}_#{pred}"] || '', html_attrs: html_attrs)
22
+ -elsif lookup_context.find_all("filch/_#{pred}").any?
23
+ =render("filch/#{pred}", f: f, datalist_id: datalist_id, attr: attr, model: model, default_value: template_config.default_values["#{attr}_#{pred}"] || '', html_attrs: html_attrs)
24
+ -else
25
+ %td{html_attrs[:label]}
26
+ = pred
27
+ %td.no_partial
28
+ -field_hash = {list: datalist_id, placeholder:"#{attr} #{pred}"}.merge(html_attrs[:field])
29
+ -field_hash[:value]= template_config.default_values["#{attr}_#{pred}"]
30
+ =f.text_field("#{attr}_#{pred}", field_hash)
@@ -0,0 +1,4 @@
1
+ %td{html_attrs[:label]}
2
+ distinct for:
3
+ %td
4
+ =f.collection_check_boxes(:uniq, model.columns.map(&:name), :to_s, :to_s)
@@ -0,0 +1,7 @@
1
+ %td.label{html_attrs[:label]} equals
2
+ %td
3
+ -# dont update datalist with _eq
4
+ - default_value ||= ''
5
+ - field_hash = {list: datalist_id, class: 'form-control', placeholder: "#{attr} equals"}
6
+ - field_hash[:value] = default_value
7
+ =f.search_field("#{attr}_eq", html_attrs[:field].merge(field_hash))
@@ -0,0 +1,26 @@
1
+ -sattrs_class = "#{template} js"
2
+ -sattrs={id: "#{model.name}_#{template}_form", class: sattrs_class, method: :post}.merge(html_attrs[:search_form])
3
+ =search_form_for @q, url: results_p, html: sattrs do |f|
4
+ %p.btn.btn-sm.js{click: 'clearAll' }
5
+ Clear All
6
+ %table{id: model.name + '_table'}
7
+ %tr
8
+ %td.attributes
9
+ =render('filch/attributes', model: model, f: f, template: template, template_config: template_config, html_attrs: html_attrs)
10
+ %tr
11
+ %td.associations
12
+ =render('filch/associations', model: model, f: f, template: template, template_config: template_config, html_attrs: html_attrs)
13
+ %tr
14
+ %td.scopes
15
+ %h4
16
+ =render('filch/scopes', model: model, f: f, template: template, template_config: template_config)
17
+ %tr
18
+ %td.options
19
+ =render('filch/options', model: model, template_config: template_config)
20
+ %tr
21
+ %td
22
+ =hidden_field_tag 'template', template
23
+ =hidden_field_tag 'model', model
24
+ - fattrs = {class: 'js submit',
25
+ attr: 'action', elem: 'word_search', attr_val: '/search'}
26
+ =f.submit("search", fattrs)
@@ -0,0 +1,4 @@
1
+ %td
2
+ group:
3
+ %td
4
+ =f.collection_check_boxes(:group, model.columns.map(&:name), :to_s, :to_s)
@@ -0,0 +1,2 @@
1
+ %td greater than
2
+ %td= f.number_field attr + '_gt'
@@ -0,0 +1,5 @@
1
+ %td limit
2
+ %td
3
+ -v = params[:q] ? params[:q][scope_name].to_s : default_value
4
+ -v ||= '50'
5
+ =f.number_field(scope_name, value: v)
@@ -0,0 +1,2 @@
1
+ %td less than
2
+ %td= f.number_field attr + '_lt'
@@ -0,0 +1,5 @@
1
+ %td.lable{html_attrs[:label]} is null?
2
+ %td
3
+ -v = params[:q] ? params[:q]["#{attr}_null"] : ''
4
+ -v = default_value || v
5
+ =f.select("#{attr}_null", {'is not null': '0', 'is null': '1'}, {include_blank: true, selected: v})
@@ -0,0 +1,11 @@
1
+ %table
2
+ -template_config.options.each do |option|
3
+ %tr{class: option}
4
+ -if lookup_context.find_all("filch/_#{option}").any?
5
+ =render("filch/#{option}", f: f, option: option, model: model, default_value: template_config.default_values[option] || [])
6
+ -else
7
+ %td
8
+ =option
9
+ %td.nopartial
10
+ =check_box_tag("o[#{option}]", 1, template_config.default_values[option] || false)
11
+
@@ -0,0 +1,4 @@
1
+ %td
2
+ Order By
3
+ %td
4
+ =f.select(scope_name, model.columns.map(&:name), {selected: default_value}, {class: 'q_s'})
@@ -0,0 +1,6 @@
1
+ %td
2
+ group for:
3
+ %td
4
+ -default_value ||= []
5
+ =f.collection_check_boxes(:pg_group, model.columns, :name, :name, {include_hidden: false}) do |box|
6
+ = box.label {default_value.include?(box.value) ? box.check_box( checked: true ) + box.text : box.check_box(checked: false) + box.text}
@@ -0,0 +1,4 @@
1
+ %td
2
+ pluck:
3
+ %td
4
+ =f.collection_check_boxes(:pluck, model.columns, :name, :name, {include_hidden: false})
@@ -0,0 +1,3 @@
1
+ -q.each do |word|
2
+ %option
3
+ =word
@@ -0,0 +1,11 @@
1
+ %table
2
+ -template_config.scopes.each do |scope_name|
3
+ %tr{class: scope_name}
4
+ -if lookup_context.find_all("filch/_#{scope_name}").any?
5
+ =render("filch/#{scope_name}", f: f, model: model, scope_name: scope_name, default_value: template_config.default_values[scope_name] || nil)
6
+ -else
7
+ %td
8
+ =scope_name
9
+ %td.nopartial
10
+ =check_box_tag("q[#{scope_name}", 1, template_config.default_values[scope_name] || false)
11
+
@@ -0,0 +1,12 @@
1
+ = javascript_include_tag 'js_weber'
2
+ = javascript_include_tag 'filch'
3
+ -button_attrs= filch.html_attrs[:button]
4
+ %button#filch_button.js.btn.btn-sm.collapsed{button_attrs}
5
+ =button_name
6
+ %span#filch
7
+ -select_h = {class: 'js', change: 'showSelected', load: 'showSelected'}
8
+ -t_keys = filch.template_keys
9
+ -if t_keys.length > 1
10
+ =select_tag 'template', options_for_select(t_keys, params[:template]), select_h
11
+ -t_keys.each do |template|
12
+ =render('filch/form', model: filch.model, template: template, template_config: filch.templates[template], results_p: results_p, html_attrs: filch.html_attrs)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'filch'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1 @@
1
+ Rails.application.config.assets.precompile += %w[filch.js]
@@ -0,0 +1,100 @@
1
+ # all this was necessary to give me a case sensitive predicate!!!
2
+ # stolen from https://github.com/activerecord-hackery/ransack/issues/699
3
+ # {{
4
+ Ransack.configure do |config|
5
+ config.add_predicate(
6
+ 'like',
7
+ arel_predicate: 's_matches',
8
+ formatter: proc { |v| "%#{v}%" },
9
+ type: :string
10
+ )
11
+ end
12
+
13
+ module Arel
14
+ module Nodes
15
+ # creates an arel predicate for case sensitive searching in postgres
16
+ class Matches < Binary
17
+ attr_reader :escape
18
+ attr_accessor :case_sensitive
19
+
20
+ def initialize(left, right, escape = nil, case_sensitive = false)
21
+ super(left, right)
22
+ @escape = escape && Nodes.build_quoted(escape)
23
+ @case_sensitive = case_sensitive
24
+ end
25
+ end
26
+
27
+ # DoesNotMatch will inherit from matches
28
+ class DoesNotMatch < Matches; end
29
+ end
30
+ end
31
+
32
+ module Arel
33
+ # adding s_metches to Arel::Predications
34
+ module Predications
35
+ # creates an arel predicate for case sensitive searching in postgres
36
+ def s_matches(other, escape = nil)
37
+ Nodes::Matches.new self, quoted_node(other), escape, true
38
+ end
39
+ end
40
+ end
41
+
42
+ module Arel
43
+ module Visitors
44
+ # changes postgres query to casesensitive
45
+ class PostgreSQL < Arel::Visitors::ToSql
46
+ private
47
+
48
+ # arel doesnt use snakecase??
49
+ def visit_Arel_Nodes_Matches(oth, col)
50
+ col = infix_value oth, col, oth.case_sensitive ? ' LIKE ' : ' ILIKE '
51
+ escape = oth.escape
52
+ return col unless escape
53
+ visit escape, col << ' ESCAPE '
54
+ end
55
+ end
56
+ end
57
+ end
58
+ # }}
59
+
60
+ # Array Contains
61
+ # {{{
62
+ # https://github.com/activerecord-hackery/ransack/issues/321
63
+ module Arel
64
+ # create arel predicate for array
65
+ module Predications
66
+ def array_cont(other)
67
+ Nodes::Equality.new(
68
+ Nodes.build_quoted(other, self), Nodes::NamedFunction.new('ANY', [self])
69
+ )
70
+ end
71
+ end
72
+ end
73
+
74
+ Ransack.configure do |config|
75
+ config.add_predicate :array_cont, arel_predicate: :array_cont
76
+ end
77
+ # }}}
78
+
79
+ # Array Not Contains
80
+ # {{{
81
+ # https://github.com/activerecord-hackery/ransack/issues/321
82
+ module Arel
83
+ # create arel predicate for not array not contains
84
+ module Predications
85
+ def array_not_cont(other)
86
+ Nodes::DoesNotMatch.new(
87
+ Nodes.build_quoted(other, self),
88
+ Nodes::NamedFunction.new('ALL', [self])
89
+ )
90
+ end
91
+ end
92
+ end
93
+
94
+ Ransack.configure do |config|
95
+ config.add_predicate :array_not_cont, arel_predicate: :array_not_cont
96
+ end
97
+ # }}}
98
+
99
+ #
100
+ # vim:foldmethod=marker
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ get 'filch/datalist' => 'filch#datalist', :as => :filch_datalist
3
+ end
@@ -0,0 +1,40 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'filch/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'filch'
7
+ spec.version = Filch::VERSION
8
+ spec.authors = ['ynweber']
9
+ spec.email = ['foo']
10
+
11
+ spec.summary = %(a search form builder.)
12
+ spec.description = %(Creates search forms based on templates configurable in
13
+ model. Using Ransack.)
14
+ spec.homepage = 'https://bitbucket.org/ynweber/filch/'
15
+ spec.license = 'MIT'
16
+
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://bitbucket.org/ynweber/filch/src'
19
+ spec.metadata['changelog_uri'] = 'https://bitbucket.org/ynweber/filch/commits/'
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been
23
+ # added into git.
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ `git ls-files -z`.split("\x0")
26
+ .reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
28
+ spec.bindir = 'exe'
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ['lib']
31
+
32
+ spec.add_dependency 'haml'
33
+ spec.add_dependency 'js_weber'
34
+ spec.add_dependency 'ransack'
35
+ spec.add_development_dependency 'bundler', '~> 2.0'
36
+ spec.add_development_dependency 'minitest', '~> 5.0'
37
+ spec.add_development_dependency 'minitest-rails'
38
+ spec.add_development_dependency 'minitest-reporters', '>= 1.1'
39
+ spec.add_development_dependency 'rake', '~> 10.0'
40
+ end
@@ -0,0 +1,375 @@
1
+ require 'filch/version'
2
+ require 'filch/engine'
3
+ require 'filch/error'
4
+ require 'filch/datalist'
5
+ require 'filch/ransack_plus'
6
+ require 'filch/model_find'
7
+
8
+ # = The Filch Gem
9
+ # the Filch Gem is entirely based on the
10
+ # ransack[https://github.com/activerecord-hackery/ransack] gem
11
+ # Filch allows for easy advanced form building.
12
+ #
13
+ # ==Features
14
+ # Filch::Templates:: The Filch::Templates object is used when generating
15
+ # the form(s).
16
+ # Filch::Datalist:: Text fields are linked to a <datalist>.
17
+ # Uses javascript to update the list with
18
+ # Filch::Datalist.quick
19
+ # Filch::RansackPlus:: Certain methods I couldn't do with Ransack/Arel.
20
+ module Filch
21
+ def self.templates(model)
22
+ Templates.new(model)
23
+ end
24
+
25
+ # calls the Filch::Datalist.quick method.
26
+ # <i>model_name</i> is a String representing the name of the model.
27
+ # <i>attr</i> is a String representing the attribute to query.
28
+ # <i>params</i> is the form's params.
29
+ #
30
+ # returns an Array 'plucked' from the results
31
+ #
32
+ # this method is usually called internally, from javascript
33
+ def self.datalist(model_name, attr, params)
34
+ Datalist.quick(model(model_name), attr, params)
35
+ end
36
+
37
+ # Filch::RansackPlus.
38
+ # recieves the form <i>params<i>, for the 'plus' methods
39
+ # <i>q</i> is the form object.
40
+ # returns an array of ransacked results
41
+ def self.ransack_plus(params, query)
42
+ RansackPlus.new(params, query)
43
+ end
44
+
45
+ # model_find should be a String representing the name of a model.
46
+ # returns a model.
47
+ # If model_find is nil, or the model is not found, return the first model.
48
+ def self.model(model_find = nil)
49
+ ModelFind.find(model_find)
50
+ end
51
+
52
+ # = Templates
53
+ # Builds a hash. keys ares are an array template_keys
54
+ # , values are Filch::Template.
55
+ # @templates[template_key] = Filch::Template.new(@model, template_key)
56
+ # template_keys can be defined in the model
57
+ # class Foo < ApplicationRecord
58
+ # def self.filch_template_keys
59
+ # %i[all basic]
60
+ # end
61
+ # end
62
+ class Templates
63
+ def initialize(model)
64
+ @model = model
65
+ @templates = build_templates
66
+ end
67
+ attr_reader :templates, :model
68
+
69
+ def html_attrs_values
70
+ {
71
+ assocs: { click: 'filchColClick', load: 'toggleShowHide' },
72
+ attrs: { click: 'filchColClick', load: 'toggleShowHide' },
73
+ button: {
74
+ click: 'toggleShowHide', shId: 'filch', load: 'toggleShowHide'
75
+ },
76
+ datalist: {
77
+ updateInner_path: '/filch/datalist', class: 'js', update: 'dlUpdate'
78
+ },
79
+ field: { class: 'js form-control', input: 'filchDataList' },
80
+ label: { class: 'cheese'}
81
+ }
82
+ end
83
+
84
+ def model_html_attrs
85
+ model_attrs = if @model.methods.include?(:filch_html_attrs)
86
+ @model.filch_html_attrs
87
+ else
88
+ {}
89
+ end
90
+ model_attrs.default = {}
91
+ model_attrs
92
+ end
93
+
94
+ def html_attrs
95
+ attrs = html_attrs_values
96
+ attrs.default = {}
97
+ attrs.each_key do |key|
98
+ attrs[key] = attrs[key].merge(model_html_attrs[key])
99
+ end
100
+ attrs
101
+ end
102
+
103
+
104
+ # def button_attrs
105
+ # attrs = {
106
+ # }
107
+ # if @model.methods.include?(:button_attrs)
108
+ # attrs = attrs.merge(@model.button_attrs) || attrs
109
+ # end
110
+ # attrs
111
+ # end
112
+
113
+ def build_templates
114
+ templates = {}
115
+ templates.default = Template.new(@model, 'default')
116
+ template_keys.each do |template|
117
+ templates[template] = Template.new(@model, template)
118
+ end
119
+ templates
120
+ end
121
+
122
+ # will generate forms based on the list of templates in the Array
123
+ # <i>YourModel.template_keys</i>.
124
+ # defaults to ['all']
125
+ def template_keys
126
+ if @model.methods.include?(:template_keys)
127
+ @model.template_keys || ['all']
128
+ else
129
+ ['all']
130
+ end
131
+ end
132
+ end
133
+
134
+ # The Template Object
135
+ # defines a template
136
+ # recieves a model Object, and a String representing the name of the template.
137
+ # returns a new object with the following attributes:
138
+ # [associations_keys] an Array of Strings representing the names of the
139
+ # the Filch::Associations to be queryed.
140
+ # [associations] a Hash of Strings representing the predicates to be queryed.
141
+ # [attribute_keys] same as association_keys, for the the Filch::Attributes
142
+ # [attributes] same as associations, for the Filch::Attributes.
143
+ # [scope_keys] same as association_keys, for the Filch::Scopes
144
+ # [scopes] same as associations, for the Filch::Scopes
145
+ class Template
146
+ def initialize(model, template)
147
+ @model = model
148
+ @template = template
149
+ @assocs = Associations.new(model)
150
+ @attrs = Attributes.new(model)
151
+ end
152
+ attr_reader :model
153
+
154
+ def attributes
155
+ @attrs.attributes[@template]
156
+ end
157
+
158
+ def attributes_keys
159
+ @attrs.attributes_keys[@template]
160
+ end
161
+
162
+ def associations
163
+ @assocs.associations[@template]
164
+ end
165
+
166
+ def associations_keys
167
+ @assocs.associations_keys[@template]
168
+ end
169
+
170
+ def df_vals
171
+ {}
172
+ end
173
+
174
+ def default_values
175
+ if @model.methods.include?(:filch_defaults)
176
+ df_vals.merge(@model.filch_defaults[@template])
177
+ else
178
+ df_vals
179
+ end
180
+ end
181
+
182
+ def options
183
+ if @model.methods.include?(:filch_options)
184
+ @model.filch_options[@template] || {}
185
+ else
186
+ {}
187
+ end
188
+ end
189
+
190
+ def scopes
191
+ Scopes.new(@model).scopes[@template]
192
+ end
193
+ end
194
+
195
+ # associations_keys, to determine which associations to query &
196
+ # #associations, to determine which predicates to query on those associations.
197
+ class Associations
198
+ def initialize(model)
199
+ @model = model
200
+ @ransackable_associations = @model ? @model.ransackable_associations : []
201
+ end
202
+
203
+ # the associated models to be queryed.
204
+ # associations_keys can be defined in the model
205
+ # class Foo < ApplicationRecord
206
+ # has_many :employees
207
+ # has_many :pay_stubs
208
+ # def self.filch_assoc_keys
209
+ # %i[employess pay_stubs]
210
+ # end
211
+ # end
212
+ #
213
+ # defaults to all ransackable_associtations
214
+ def associations_keys
215
+ assoc_keys =
216
+ if @model.methods.include?(:filch_assoc_keys)
217
+ @model.filch_assoc_keys
218
+ else
219
+ {}
220
+ end
221
+ assoc_keys.default = @ransackable_associations
222
+ assoc_keys[:all] = @ransackable_associations
223
+ assoc_keys
224
+ end
225
+
226
+ # a hash representing all the predicates to be queryed for a given
227
+ # association.
228
+ # #associations can be defined in the model
229
+ # class Foo < ApplicationRecord
230
+ # has_many :employees
231
+ # has_many :pay_stubs
232
+ # def self.filch_associations
233
+ # {
234
+ # basic_template: {
235
+ # employee: {
236
+ # name: %w[eq cont]
237
+ # },
238
+ # pay_stub: {
239
+ # year: %w[eq gt]
240
+ # }
241
+ # }
242
+ # }
243
+ # end
244
+ # end
245
+ #
246
+ # defaults to all ransackable_attributes for a given association with a
247
+ # value of ['eq']
248
+ def associations
249
+ assoc_hash =
250
+ if @model.methods.include?(:filch_associations)
251
+ @model.filch_associations
252
+ else
253
+ {}
254
+ end
255
+ assoc_hash.default = all
256
+ assoc_hash[:all] = all
257
+ assoc_hash
258
+ end
259
+
260
+ # TODO: specialize defaults to class types
261
+ # using class_eval(assoc.capitalize).columns
262
+ # doesnt work if belongs_to is not the same name as class
263
+ def all
264
+ @ransackable_associations.each_with_object({}) do |assoc, all_hash|
265
+ all_hash[assoc] = Hash.new(['eq'])
266
+ next unless Object.const_defined?(assoc.capitalize)
267
+ all_hash_assoc(all_hash, assoc)
268
+ # assoc_class_name = assoc.capitalize
269
+ end
270
+ end
271
+
272
+ def all_hash_assoc(all_hash, assoc)
273
+ Object.const_get(assoc.capitalize).ransackable_attributes
274
+ .each { |attr| all_hash[assoc][attr] = ['eq'] }
275
+ all_hash
276
+ end
277
+ end
278
+
279
+ # similar to Filch::Associations, except doesn't use predicates, and
280
+ # ransackable_scopes <b>must be</b> defined.
281
+ # class Foo < ApplicationRecord
282
+ # scope :managers, -> { where(position: 'Manager') }
283
+ # scope :store_managers, -> { where(position: 'StoreManager') }
284
+ # def self.ransackable_scopes
285
+ # %w[managers, store_managers]
286
+ # end
287
+ # end
288
+ #
289
+ # defaults to <i>ransackable_scopes</i>
290
+ class Scopes
291
+ def initialize(model)
292
+ @model = model
293
+ end
294
+
295
+ # can be defined on the model
296
+ # class Foo < ApplicationRecord
297
+ # def self.filch_scopes
298
+ # %w[managers, store_managers]
299
+ def scopes
300
+ scopes_hash = Hash.new(default)
301
+ if @model.methods.include?(:filch_scopes)
302
+ scopes_hash = scopes_hash.merge(@model.filch_scopes)
303
+ end
304
+ scopes_hash[:all] = @model ? @model.ransackable_scopes : []
305
+ scopes_hash
306
+ end
307
+
308
+ def default
309
+ default_hash = {}
310
+ default_hash
311
+ end
312
+ end
313
+
314
+ # similar to Filch::Associations
315
+ class Attributes
316
+ def initialize(model)
317
+ @model = model
318
+ @ransackable_attributes = @model ? @model.ransackable_attributes : []
319
+ end
320
+
321
+ # defaults to <i>Foo.ransackable_attributes</i>
322
+ def attributes_keys
323
+ attributes_keys =
324
+ @model.methods.include?(:filch_attrs) ? @model.filch_attrs : {}
325
+ attributes_keys.default = @ransackable_attributes
326
+ attributes_keys[:all] = @ransackable_attributes
327
+ attributes_keys
328
+ end
329
+
330
+ def attributes
331
+ attributes_hash = Hash.new(default)
332
+ if @model.methods.include?(:filch_attributes)
333
+ # attributes_hash.merge(@model.filch_attributes)
334
+ attributes_hash = attributes_hash.merge(@model.filch_attributes)
335
+ end
336
+ # attributes_hash = default_values(attributes_hash)
337
+ attributes_hash.each_value { |template_h| template_h.default = ['eq'] }
338
+ attributes_hash
339
+ end
340
+
341
+ def all
342
+ all_hash = {}
343
+ @ransackable_attributes.each do |attr|
344
+ all_hash[attr] = types[attr_columns(attr)]
345
+ end
346
+ all_hash
347
+ end
348
+
349
+ def attr_columns(attr)
350
+ @model.columns.select { |col| col.name == attr }.first.type
351
+ end
352
+
353
+ def default
354
+ def_hash = Hash.new(['eq'])
355
+ def_hash[:all] = all
356
+ def_hash
357
+ end
358
+
359
+ # TODO: setup defaults based on column_type
360
+ def types
361
+ {
362
+ integer: %w[eq lt gt],
363
+ string: %w[null eq start matches],
364
+ text: types_hash['string'],
365
+ boolean: %w[null]
366
+ }
367
+ end
368
+
369
+ def types_hash
370
+ {
371
+ string: ['eq']
372
+ }
373
+ end
374
+ end
375
+ end