filch 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +303 -0
- data/Rakefile +10 -0
- data/app/controllers/filch_controller.rb +13 -0
- data/app/views/filch/_associations.html.haml +25 -0
- data/app/views/filch/_attributes.html.haml +30 -0
- data/app/views/filch/_distinct.html.haml +4 -0
- data/app/views/filch/_eq.html.haml +7 -0
- data/app/views/filch/_form.html.haml +26 -0
- data/app/views/filch/_group.html.haml +4 -0
- data/app/views/filch/_gt.html.haml +2 -0
- data/app/views/filch/_limit.html.haml +5 -0
- data/app/views/filch/_lt.html.haml +2 -0
- data/app/views/filch/_null.html.haml +5 -0
- data/app/views/filch/_options.html.haml +11 -0
- data/app/views/filch/_order.html.haml +4 -0
- data/app/views/filch/_pg_group.html.haml +6 -0
- data/app/views/filch/_pluck.html.haml +4 -0
- data/app/views/filch/_quick.html.haml +3 -0
- data/app/views/filch/_scopes.html.haml +11 -0
- data/app/views/filch/_search.html.haml +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/ransack.rb +100 -0
- data/config/routes.rb +3 -0
- data/filch.gemspec +40 -0
- data/lib/filch.rb +375 -0
- data/lib/filch/datalist.rb +26 -0
- data/lib/filch/engine.rb +5 -0
- data/lib/filch/error.rb +4 -0
- data/lib/filch/model_find.rb +17 -0
- data/lib/filch/ransack_plus.rb +34 -0
- data/lib/filch/version.rb +3 -0
- data/vendor/assets/javascripts/filch.js +1 -0
- data/vendor/assets/javascripts/filchColClick.js +6 -0
- data/vendor/assets/javascripts/filchDataList.js +21 -0
- data/vendor/assets/javascripts/unhideForm.js +19 -0
- 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,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,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,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,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)
|
data/bin/console
ADDED
@@ -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__)
|
data/bin/setup
ADDED
@@ -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
|
data/config/routes.rb
ADDED
data/filch.gemspec
ADDED
@@ -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
|
data/lib/filch.rb
ADDED
@@ -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
|