filch 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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