discerner 1.1.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +97 -0
- data/Rakefile +29 -0
- data/app/assets/images/discerner/add.png +0 -0
- data/app/assets/images/discerner/ajax-loader.gif +0 -0
- data/app/assets/images/discerner/bar.gif +0 -0
- data/app/assets/images/discerner/bullet_arrow_down.png +0 -0
- data/app/assets/images/discerner/bullet_arrow_up.png +0 -0
- data/app/assets/images/discerner/cog.png +0 -0
- data/app/assets/images/discerner/delete.png +0 -0
- data/app/assets/images/discerner/edit.png +0 -0
- data/app/assets/images/discerner/excel.png +0 -0
- data/app/assets/images/discerner/greencheck.gif +0 -0
- data/app/assets/images/discerner/rails.png +0 -0
- data/app/assets/images/discerner/show.png +0 -0
- data/app/assets/images/discerner/switch_minus.gif +0 -0
- data/app/assets/images/discerner/switch_plus.gif +0 -0
- data/app/assets/javascripts/discerner/application.js +20 -0
- data/app/assets/javascripts/discerner/combobox.js +301 -0
- data/app/assets/javascripts/discerner/discerner.js +19 -0
- data/app/assets/javascripts/discerner/export_parameters.js +13 -0
- data/app/assets/javascripts/discerner/jquery/jquery.blockUI.js +576 -0
- data/app/assets/javascripts/discerner/jquery/jquery.form.js +1074 -0
- data/app/assets/javascripts/discerner/nested_attributes.js +69 -0
- data/app/assets/javascripts/discerner/search_combinations.js +49 -0
- data/app/assets/javascripts/discerner/search_parameter.js +131 -0
- data/app/assets/javascripts/discerner/search_parameter_value.js +172 -0
- data/app/assets/javascripts/discerner/searches.js +93 -0
- data/app/assets/javascripts/discerner/url.js +42 -0
- data/app/assets/stylesheets/discerner/application.css +16 -0
- data/app/assets/stylesheets/discerner/buttons.sass +13 -0
- data/app/assets/stylesheets/discerner/categorized_autocompleter.sass +53 -0
- data/app/assets/stylesheets/discerner/discerner.sass +51 -0
- data/app/assets/stylesheets/discerner/export_parameters.sass +43 -0
- data/app/assets/stylesheets/discerner/links.sass +29 -0
- data/app/assets/stylesheets/discerner/searches.sass +205 -0
- data/app/assets/stylesheets/discerner/tables.sass +32 -0
- data/app/controllers/discerner/application_controller.rb +2 -0
- data/app/controllers/discerner/export_parameters_controller.rb +5 -0
- data/app/controllers/discerner/parameters_controller.rb +5 -0
- data/app/controllers/discerner/searches_controller.rb +5 -0
- data/app/helpers/discerner/application_helper.rb +4 -0
- data/app/helpers/discerner/parameters_helper.rb +5 -0
- data/app/helpers/discerner/searches_helper.rb +5 -0
- data/app/models/discerner/dictionary.rb +5 -0
- data/app/models/discerner/export_parameter.rb +5 -0
- data/app/models/discerner/operator.rb +5 -0
- data/app/models/discerner/parameter.rb +5 -0
- data/app/models/discerner/parameter_category.rb +5 -0
- data/app/models/discerner/parameter_type.rb +5 -0
- data/app/models/discerner/parameter_value.rb +5 -0
- data/app/models/discerner/parameter_value_categorization.rb +5 -0
- data/app/models/discerner/parameter_value_category.rb +5 -0
- data/app/models/discerner/search.rb +5 -0
- data/app/models/discerner/search_combination.rb +5 -0
- data/app/models/discerner/search_parameter.rb +5 -0
- data/app/models/discerner/search_parameter_value.rb +5 -0
- data/app/views/discerner/export_parameters/index.html.haml +55 -0
- data/app/views/discerner/parameters/_values_autocompleter.html.haml +49 -0
- data/app/views/discerner/parameters/values.html.haml +1 -0
- data/app/views/discerner/searches/_form.html.haml +21 -0
- data/app/views/discerner/searches/_form_combined_searches.html.haml +32 -0
- data/app/views/discerner/searches/_form_controls.html.haml +8 -0
- data/app/views/discerner/searches/_form_header.html.haml +39 -0
- data/app/views/discerner/searches/_form_search_parameters.html.haml +28 -0
- data/app/views/discerner/searches/_list.html.haml +17 -0
- data/app/views/discerner/searches/_search_combination_fields.html.haml +22 -0
- data/app/views/discerner/searches/_search_parameter_fields.html.haml +48 -0
- data/app/views/discerner/searches/_search_parameter_value_fields.html.haml +62 -0
- data/app/views/discerner/searches/_summary.html.haml +25 -0
- data/app/views/discerner/searches/edit.html.haml +8 -0
- data/app/views/discerner/searches/index.html.haml +13 -0
- data/app/views/discerner/searches/index.js.haml +1 -0
- data/app/views/discerner/searches/new.html.haml +3 -0
- data/app/views/discerner/searches/rename.html.haml +6 -0
- data/app/views/discerner/searches/update.js.haml +7 -0
- data/app/views/discerner/shared/_categorized_autocompleter_items.html.haml +15 -0
- data/app/views/discerner/shared/_error_messages.html.haml +5 -0
- data/app/views/layouts/discerner/searches.html.erb +17 -0
- data/config/cucumber.yml +8 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20121004040716_create_discerner_dictionaries.rb +11 -0
- data/db/migrate/20121004153043_create_discerner_parameter_categories.rb +12 -0
- data/db/migrate/20121005194843_create_discerner_parameter_types.rb +11 -0
- data/db/migrate/20121005203223_create_discerner_parameters.rb +14 -0
- data/db/migrate/20121008154855_create_discerner_operators.rb +13 -0
- data/db/migrate/20121008160313_create_discerner_operators_parameter_types.rb +8 -0
- data/db/migrate/20121008161455_create_discerner_parameter_values.rb +13 -0
- data/db/migrate/20121008180829_create_discerner_searches.rb +11 -0
- data/db/migrate/20121008182443_create_discerner_search_parameters.rb +11 -0
- data/db/migrate/20121011205130_create_discerner_search_parameter_values.rb +15 -0
- data/db/migrate/20121211213215_add_dictionary_id_to_discerner_searches.rb +5 -0
- data/db/migrate/20130205193602_create_discerner_search_combinations.rb +12 -0
- data/db/migrate/20130211230636_create_discerner_export_parameters.rb +9 -0
- data/db/migrate/20130213185818_add_search_columns_to_discerner_parameters.rb +38 -0
- data/db/migrate/20130213205255_rename_database_name_to_search_value_in_discerner_parameter_values.rb +5 -0
- data/db/migrate/20130215165416_add_searchable_to_discerner_parameters.rb +5 -0
- data/db/migrate/20130218230257_add_exclusive_to_discerner_parameters.rb +5 -0
- data/db/migrate/20130220163015_replace_integer_type_with_numeric.rb +22 -0
- data/db/migrate/20130221172826_add_unique_identifier_to_discerner_parameters.rb +5 -0
- data/db/migrate/20130222052924_change_search_attribute_to_method.rb +29 -0
- data/db/migrate/20130222070959_add_export_columns_to_discerner_parameters.rb +6 -0
- data/db/migrate/20130227031747_add_unique_identifier_to_discerner_operators.rb +16 -0
- data/db/migrate/20130306015019_change_discerner_parameter_values_name.rb +9 -0
- data/db/migrate/20130306212430_add_deleted_at_to_discerner_search_parameters.rb +5 -0
- data/db/migrate/20130306212504_add_deleted_at_to_discerner_search_parameter_values.rb +5 -0
- data/db/migrate/20130306212527_add_deleted_at_to_discerner_search_combinations.rb +5 -0
- data/db/migrate/20130306212818_add_deleted_at_to_discerner_export_parameters.rb +5 -0
- data/db/migrate/20130311190717_add_operator_type_to_discerner_operators.rb +5 -0
- data/db/migrate/20131212175110_remove_extra_search_parameter_values.rb +10 -0
- data/db/migrate/20140204170625_create_discerner_parameter_value_categories.rb +16 -0
- data/db/migrate/20140204170646_create_discerner_parameter_value_categorizations.rb +12 -0
- data/db/migrate/20140227191827_remove_blank_parameter_values_from_export_parameters.rb +10 -0
- data/db/seeds.rb +0 -0
- data/lib/discerner/engine.rb +16 -0
- data/lib/discerner/methods/controllers/export_parameters_controller.rb +38 -0
- data/lib/discerner/methods/controllers/parameters_controller.rb +30 -0
- data/lib/discerner/methods/controllers/searches_controller.rb +204 -0
- data/lib/discerner/methods/helpers/searches_helper.rb +145 -0
- data/lib/discerner/methods/models/dictionary.rb +54 -0
- data/lib/discerner/methods/models/export_parameter.rb +35 -0
- data/lib/discerner/methods/models/operator.rb +42 -0
- data/lib/discerner/methods/models/parameter.rb +90 -0
- data/lib/discerner/methods/models/parameter_category.rb +60 -0
- data/lib/discerner/methods/models/parameter_type.rb +33 -0
- data/lib/discerner/methods/models/parameter_value.rb +87 -0
- data/lib/discerner/methods/models/parameter_value_categorization.rb +21 -0
- data/lib/discerner/methods/models/parameter_value_category.rb +45 -0
- data/lib/discerner/methods/models/search.rb +147 -0
- data/lib/discerner/methods/models/search_combination.rb +50 -0
- data/lib/discerner/methods/models/search_parameter.rb +128 -0
- data/lib/discerner/methods/models/search_parameter_value.rb +130 -0
- data/lib/discerner/methods/models/soft_delete.rb +35 -0
- data/lib/discerner/methods/models/warning.rb +15 -0
- data/lib/discerner/parser.rb +497 -0
- data/lib/discerner/version.rb +3 -0
- data/lib/discerner.rb +4 -0
- data/lib/generators/discerner/dictionary/dictionary_generator.rb +38 -0
- data/lib/generators/discerner/dictionary/templates/model.rb +15 -0
- data/lib/generators/discerner/dictionary/templates/show.xls.erb +37 -0
- data/lib/generators/discerner/dictionary/templates/view.html.haml +2 -0
- data/lib/generators/discerner/install/install_generator.rb +153 -0
- data/lib/generators/discerner/install/templates/controllers/export_parameters_controller.rb +20 -0
- data/lib/generators/discerner/install/templates/controllers/parameters_controller.rb +15 -0
- data/lib/generators/discerner/install/templates/controllers/searches_controller.rb +39 -0
- data/lib/generators/discerner/install/templates/dictionaries.yml +236 -0
- data/lib/generators/discerner/install/templates/helpers/searches_helper.rb +9 -0
- data/lib/generators/discerner/install/templates/models/book.rb +15 -0
- data/lib/generators/discerner/install/templates/models/dictionary.rb +9 -0
- data/lib/generators/discerner/install/templates/models/export_parameter.rb +9 -0
- data/lib/generators/discerner/install/templates/models/operator.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter.rb +10 -0
- data/lib/generators/discerner/install/templates/models/parameter_category.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter_type.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter_value.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter_value_categorization.rb +9 -0
- data/lib/generators/discerner/install/templates/models/parameter_value_category.rb +9 -0
- data/lib/generators/discerner/install/templates/models/search.rb +9 -0
- data/lib/generators/discerner/install/templates/models/search_combination.rb +9 -0
- data/lib/generators/discerner/install/templates/models/search_parameter.rb +9 -0
- data/lib/generators/discerner/install/templates/models/search_parameter_value.rb +9 -0
- data/lib/generators/discerner/install/templates/views/layouts/searches.html.erb +17 -0
- data/lib/setup/operators.yml +91 -0
- data/lib/tasks/cucumber.rake +65 -0
- data/lib/tasks/discerner_tasks.rake +30 -0
- metadata +531 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module ExportParameter
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
|
8
|
+
# Associations
|
9
|
+
base.send :belongs_to, :parameter, :inverse_of => :export_parameters
|
10
|
+
base.send :belongs_to, :search, :inverse_of => :export_parameters
|
11
|
+
|
12
|
+
# Scopes
|
13
|
+
base.send(:scope, :ordered, -> { base.order('discerner_export_parameters.id ASC') })
|
14
|
+
base.send(:scope, :by_parameter_category, ->(parameter_category) { base.includes(:parameter).where('discerner_parameters.parameter_category_id' => parameter_category.id) unless parameter_category.blank?})
|
15
|
+
|
16
|
+
# Validations
|
17
|
+
base.send :validates, :parameter, :search, :presence => { :message => "for export parameter can't be blank" }
|
18
|
+
|
19
|
+
# Whitelisting attributes
|
20
|
+
base.send :attr_accessible, :parameter_id, :search_id, :parameter, :search
|
21
|
+
end
|
22
|
+
|
23
|
+
# Instance Methods
|
24
|
+
def initialize(*args)
|
25
|
+
super(*args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def disabled?
|
29
|
+
return false unless persisted?
|
30
|
+
deleted? || parameter.blank? || parameter.deleted?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module Operator
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
|
8
|
+
# Associations
|
9
|
+
base.send :has_many, :search_parameter_values, :inverse_of => :operator
|
10
|
+
base.send :has_many, :search_combinations, :inverse_of => :operator
|
11
|
+
base.send :has_and_belongs_to_many, :parameter_types, :join_table => :discerner_operators_parameter_types
|
12
|
+
|
13
|
+
# Validations
|
14
|
+
base.send :validates, :symbol, :presence => true, :uniqueness => {:message => "for operator has already been taken"}
|
15
|
+
base.send :validates, :operator_type, :presence => true
|
16
|
+
base.send :validate, :type_supported?
|
17
|
+
|
18
|
+
# Whitelisting attributes
|
19
|
+
base.send :attr_accessible, :operator_type, :symbol, :text, :deleted_at
|
20
|
+
end
|
21
|
+
|
22
|
+
# Instance Methods
|
23
|
+
def initialize(*args)
|
24
|
+
super(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def css_class_name
|
28
|
+
css_class = parameter_types.map{ |t| t.name }
|
29
|
+
css_class << operator_type unless operator_type.blank?
|
30
|
+
css_class.join(' ')
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def type_supported?
|
35
|
+
return if self.operator_type.blank?
|
36
|
+
supported_types = ['comparison', 'text_comparison', 'range', 'list', 'presence']
|
37
|
+
errors.add(:base,"Operator type '#{self.operator_type}' is not supported, please use one of the following types: #{supported_types.join(', ')}") unless supported_types.include?(self.operator_type)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module Parameter
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
|
8
|
+
# Associations
|
9
|
+
base.send :belongs_to, :parameter_category, :inverse_of => :parameters
|
10
|
+
base.send :belongs_to, :parameter_type, :inverse_of => :parameters
|
11
|
+
base.send :has_many, :parameter_values, :inverse_of => :parameter, :dependent => :destroy
|
12
|
+
base.send :has_many, :search_parameters, :inverse_of => :parameter, :dependent => :destroy
|
13
|
+
base.send :has_many, :export_parameters, :inverse_of => :parameter, :dependent => :destroy
|
14
|
+
base.send :has_many, :parameter_value_categories, :inverse_of => :parameter, :dependent => :destroy
|
15
|
+
|
16
|
+
#Validations
|
17
|
+
base.send :validates, :name, :unique_identifier, :parameter_category, :presence => { :message => "for parameter can't be blank" }
|
18
|
+
base.send :validate, :validate_unique_identifier
|
19
|
+
base.send :validate, :validate_search_attributes
|
20
|
+
base.send :validate, :validate_export_attributes
|
21
|
+
|
22
|
+
# Scopes
|
23
|
+
base.send(:scope, :searchable, -> {base.not_deleted.where('search_model is not null and search_method is not null')})
|
24
|
+
base.send(:scope, :exportable, -> {base.not_deleted.where('export_model is not null and export_method is not null')})
|
25
|
+
|
26
|
+
# Hooks
|
27
|
+
base.send :after_commit, :cascade_delete_parameter_values, :on => :update, :if => Proc.new { |record| record.previous_changes.include?('deleted_at') }
|
28
|
+
|
29
|
+
# Whitelisting attributes
|
30
|
+
base.send :attr_accessible, :name, :parameter_category, :parameter_category_id, :parameter_type, :parameter_type_id,
|
31
|
+
:search_model, :search_method, :unique_identifier, :export_model, :export_method
|
32
|
+
end
|
33
|
+
|
34
|
+
# Instance Methods
|
35
|
+
def initialize(*args)
|
36
|
+
super(*args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def used_in_search?
|
40
|
+
search_parameters.any? || export_parameters.any?
|
41
|
+
end
|
42
|
+
|
43
|
+
def display_name
|
44
|
+
"#{parameter_category.name} - #{name}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def css_class_name
|
48
|
+
css_class_array = [parameter_type.name, parameter_category.css_class_name, parameter_category.dictionary.css_class_name]
|
49
|
+
css_class_array << 'exclusive' if exclusive
|
50
|
+
css_class_array.join(' ')
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def validate_search_parameters
|
55
|
+
errors.add(:base,"Search should have at least one search criteria.") if
|
56
|
+
self.search_parameters.size < 1 || self.search_parameters.all?{|search_parameter| search_parameter.marked_for_destruction? }
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_unique_identifier
|
60
|
+
return if self.parameter_category.blank?
|
61
|
+
existing_parameters = Discerner::Parameter.
|
62
|
+
joins({ :parameter_category => :dictionary }).
|
63
|
+
where('discerner_dictionaries.id = ? and discerner_parameters.unique_identifier = ?', self.parameter_category.dictionary.id, self.unique_identifier)
|
64
|
+
existing_parameters = existing_parameters.where('discerner_parameters.id != ?', self.id) unless self.id.blank?
|
65
|
+
errors.add(:base,"Unique identifier has to be unique within dictionary.") if existing_parameters.any?
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate_search_attributes
|
69
|
+
unless self.search_model.blank? && self.search_method.blank?
|
70
|
+
errors.add(:base,"Searchable parameter should have search model, search method and parameter_type defined.") if self.search_model.blank? || self.search_method.blank? || self.parameter_type.blank?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def validate_export_attributes
|
75
|
+
unless self.export_model.blank? && self.export_method.blank?
|
76
|
+
errors.add(:base,"Exportable parameter should have export model and search method defined.") if self.export_model.blank? || self.export_method.blank?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def cascade_delete_parameter_values
|
81
|
+
return unless deleted?
|
82
|
+
parameter_values.each do |pv|
|
83
|
+
pv.deleted_at = Time.now
|
84
|
+
pv.save
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module ParameterCategory
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
|
8
|
+
# Associations
|
9
|
+
base.send :belongs_to, :dictionary, :inverse_of => :parameter_categories
|
10
|
+
base.send :has_many, :parameters, :inverse_of => :parameter_category, :dependent => :destroy
|
11
|
+
|
12
|
+
# Validations
|
13
|
+
base.send :validates, :name, :presence => true, :uniqueness => { :scope => :dictionary_id, :message => "for parameter category has already been taken"}
|
14
|
+
base.send :validates, :dictionary, :presence => { :message => "for parameter category can't be blank" }
|
15
|
+
|
16
|
+
# Scopes
|
17
|
+
base.send(:scope, :searchable, -> {base.includes(:parameters).where('discerner_parameters.search_model is not null and discerner_parameters.search_method is not null and discerner_parameters.deleted_at is null')})
|
18
|
+
base.send(:scope, :exportable, -> {base.includes(:parameters).where('discerner_parameters.export_model is not null and discerner_parameters.export_method is not null and discerner_parameters.deleted_at is null')})
|
19
|
+
base.send(:scope, :ordered_by_name, -> {base.order('discerner_parameter_categories.name ASC')})
|
20
|
+
|
21
|
+
# Hooks
|
22
|
+
base.send :after_commit, :cascade_delete_parameters, :on => :update, :if => Proc.new { |record| record.previous_changes.include?('deleted_at') }
|
23
|
+
|
24
|
+
# Whitelisting attributes
|
25
|
+
base.send :attr_accessible, :deleted_at, :dictionary, :dictionary_id, :name
|
26
|
+
end
|
27
|
+
|
28
|
+
# Instance Methods
|
29
|
+
def initialize(*args)
|
30
|
+
super(*args)
|
31
|
+
end
|
32
|
+
|
33
|
+
def parameterized_name
|
34
|
+
name.parameterize.underscore
|
35
|
+
end
|
36
|
+
|
37
|
+
def searchable_parameters
|
38
|
+
parameters.searchable
|
39
|
+
end
|
40
|
+
|
41
|
+
def exportable_parameters
|
42
|
+
parameters.exportable
|
43
|
+
end
|
44
|
+
|
45
|
+
def css_class_name
|
46
|
+
"parameter_category_#{parameterized_name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def cascade_delete_parameters
|
51
|
+
return unless deleted?
|
52
|
+
parameters.each do |p|
|
53
|
+
p.deleted_at = Time.now
|
54
|
+
p.save
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module ParameterType
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
|
8
|
+
# Associations
|
9
|
+
base.send :has_many, :parameters, :inverse_of => :parameter_type
|
10
|
+
base.send :has_and_belongs_to_many, :operators, :join_table => :discerner_operators_parameter_types
|
11
|
+
|
12
|
+
# Validations
|
13
|
+
base.send :validates, :name, :presence => true, :uniqueness => {:message => "for parameter type has already been taken"}
|
14
|
+
base.send :validate, :name_supported?
|
15
|
+
|
16
|
+
# Whitelisting attributes
|
17
|
+
base.send :attr_accessible, :deleted_at, :name
|
18
|
+
end
|
19
|
+
|
20
|
+
# Instance Methods
|
21
|
+
def initialize(*args)
|
22
|
+
super(*args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def name_supported?
|
26
|
+
return if self.name.blank?
|
27
|
+
supported_types = ['numeric', 'date', 'list', 'combobox', 'text', 'string', 'search']
|
28
|
+
errors.add(:base,"Parameter type '#{self.name}' is not supported, please use one of the following types: #{supported_types.join(', ')}") unless supported_types.include?(self.name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module ParameterValue
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
|
8
|
+
# Associations
|
9
|
+
base.send :belongs_to, :parameter, :inverse_of => :parameter_values
|
10
|
+
base.send :has_many, :search_parameter_values, :inverse_of => :parameter_value, :dependent => :destroy
|
11
|
+
base.send :has_one, :parameter_value_categorization, :inverse_of => :parameter_value, :dependent => :destroy
|
12
|
+
base.send :has_one, :parameter_value_category, :through=> :parameter_value_categorization
|
13
|
+
|
14
|
+
# Scopes
|
15
|
+
base.send(:scope, :ordered_by_name, -> { base.order('discerner_parameter_values.name ASC') })
|
16
|
+
base.send(:scope, :ordered_by_parameter_and_name, -> { base.order('discerner_parameter_values.parameter_id ASC, discerner_parameter_values.name ASC') })
|
17
|
+
|
18
|
+
#Validations
|
19
|
+
base.send :validates, :parameter, :presence => true
|
20
|
+
base.send :validates, :search_value, :length => { :maximum => 1000 }, :uniqueness => {:scope => :parameter_id, :message => "for parameter value has already been taken"}
|
21
|
+
base.send :validates, :name, :presence => true, :length => { :maximum => 1000 }
|
22
|
+
base.send :validate, :parameter_category_belongs_to_parameter
|
23
|
+
|
24
|
+
# Hooks
|
25
|
+
base.send :after_commit, :create_search_parameter_values, :on => :create
|
26
|
+
base.send :after_commit, :update_search_parameter_values, :on => :update, :if => Proc.new { |record| record.previous_changes.include?('deleted_at') }
|
27
|
+
base.send :scope, :categorized, -> {base.joins(:parameter_value_category)}
|
28
|
+
base.send :scope, :uncategorized, -> {base.includes(:parameter_value_category).where(:discerner_parameter_value_categories => {:name => nil})}
|
29
|
+
|
30
|
+
# Whitelisting attributes
|
31
|
+
base.send :attr_accessible, :search_value, :name, :parameter, :parameter_id
|
32
|
+
end
|
33
|
+
|
34
|
+
# Instance Methods
|
35
|
+
def initialize(*args)
|
36
|
+
super(*args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def used_in_search?
|
40
|
+
if parameter.parameter_type.name == 'list'
|
41
|
+
search_parameter_values.chosen.any?
|
42
|
+
else
|
43
|
+
search_parameter_values.any?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def display_name
|
48
|
+
if parameter_value_category
|
49
|
+
"#{parameter_value_category.name} - #{name} "
|
50
|
+
else
|
51
|
+
name
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def parameter_category_belongs_to_parameter
|
57
|
+
unless parameter_value_category.blank?
|
58
|
+
errors.add(:base,"Parameter category #{parameter_value_category.name} does not belong to parameter #{parameter.name}") unless parameter_value_category.parameter_id == parameter.id
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_search_parameter_values
|
63
|
+
# create additional search_parameter_values for list search_parameters so they can be dislayed as nested attribures
|
64
|
+
return if parameter.blank? || parameter.parameter_type.blank?
|
65
|
+
if parameter.parameter_type.name == 'list'
|
66
|
+
parameter.search_parameters.each do |sp|
|
67
|
+
if sp.search_parameter_values.where(:parameter_value_id => id).blank?
|
68
|
+
max_display_order = sp.search_parameter_values.ordered_by_display_order.last.display_order || -1
|
69
|
+
sp.search_parameter_values.build(:parameter_value_id => id, :display_order => max_display_order + 1)
|
70
|
+
sp.save
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def update_search_parameter_values
|
77
|
+
create_search_parameter_values
|
78
|
+
# destroy search_parameter_values that reference this value but are not chosen (list options)
|
79
|
+
return unless deleted?
|
80
|
+
search_parameter_values.each do |spv|
|
81
|
+
spv.destroy if parameter.parameter_type.name == 'list' && !spv.chosen
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module ParameterValueCategorization
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
|
8
|
+
# Associations
|
9
|
+
base.send :belongs_to, :parameter_value_category, :inverse_of => :parameter_value_categorizations
|
10
|
+
base.send :belongs_to, :parameter_value, :inverse_of => :parameter_value_categorization
|
11
|
+
|
12
|
+
# Validations
|
13
|
+
base.send :validates_presence_of, :parameter_value_category, :parameter_value
|
14
|
+
|
15
|
+
# Whitelisting attributes
|
16
|
+
base.send :attr_accessible, :parameter_value_category_id, :parameter_value_id, :parameter_value_category, :parameter_value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module ParameterValueCategory
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
|
8
|
+
# Associations
|
9
|
+
base.send :belongs_to, :parameter, :inverse_of => :parameter_value_categories
|
10
|
+
base.send :has_many, :parameter_value_categorizations, :dependent => :destroy
|
11
|
+
base.send :has_many, :parameter_values, :through => :parameter_value_categorizations
|
12
|
+
|
13
|
+
# Scopes
|
14
|
+
base.send(:scope, :ordered_by_name, -> { base.order('discerner_parameter_value_categories.name ASC') })
|
15
|
+
base.send(:scope, :ordered_by_display_order_and_name, -> { base.order('discerner_parameter_value_categories.display_order ASC, discerner_parameter_value_categories.name ASC') })
|
16
|
+
|
17
|
+
# Validations
|
18
|
+
base.send :validates_presence_of, :parameter, :unique_identifier, :name
|
19
|
+
base.send :validates, :unique_identifier, :uniqueness => {:scope => [:parameter_id, :deleted_at], :message => "for parameter value category has already been taken"}
|
20
|
+
base.send :validate, :parameter_value_belongs_to_parameter
|
21
|
+
|
22
|
+
# Whitelisting attributes
|
23
|
+
base.send :attr_accessible, :parameter, :parameter_id, :unique_identifier, :name
|
24
|
+
end
|
25
|
+
|
26
|
+
def css_class
|
27
|
+
"parameter_value_category_#{parameterized_name}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def parameterized_name
|
31
|
+
name.parameterize.underscore
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def parameter_value_belongs_to_parameter
|
36
|
+
unless parameter.blank?
|
37
|
+
parameter_values.each do |parameter_value|
|
38
|
+
errors.add(:base,"Parameter value #{parameter_value.name} does not belong to parameter #{parameter.name}") unless parameter_value.parameter_id == parameter.id
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module Search
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
base.send :include, Warning
|
8
|
+
|
9
|
+
# Associations
|
10
|
+
base.send :belongs_to, :dictionary
|
11
|
+
base.send :has_many, :search_parameters, :inverse_of => :search
|
12
|
+
base.send :has_many, :search_combinations, :inverse_of => :search
|
13
|
+
base.send :has_many, :combined_searches, :through => :search_combinations
|
14
|
+
base.send :has_many, :export_parameters, :inverse_of => :search
|
15
|
+
|
16
|
+
# Validations
|
17
|
+
base.send :validates, :dictionary, :presence => { :message => "for search can't be blank" }
|
18
|
+
base.send :validate, :validate_search_parameters
|
19
|
+
|
20
|
+
# Scopes
|
21
|
+
base.send(:scope, :by_user, ->(username) { base.where(:username => username) unless username.blank?})
|
22
|
+
|
23
|
+
# Nested attributes
|
24
|
+
base.send :accepts_nested_attributes_for, :search_parameters, :allow_destroy => true,
|
25
|
+
:reject_if => proc { |attributes| attributes['parameter_id'].blank? && attributes['parameter'].blank? }
|
26
|
+
|
27
|
+
base.send :accepts_nested_attributes_for, :search_combinations, :allow_destroy => true,
|
28
|
+
:reject_if => proc { |attributes| attributes['combined_search_id'].blank? && attributes['combined_search'].blank? }
|
29
|
+
|
30
|
+
# Hooks
|
31
|
+
base.send :after_commit, :update_associations, :on => :update, :if => Proc.new { |record| record.previous_changes.include?('deleted_at') }
|
32
|
+
|
33
|
+
# Whitelisting attributes
|
34
|
+
base.send :attr_accessible, :deleted_at, :name, :username, :search_parameters, :search_parameters_attributes,
|
35
|
+
:dictionary, :dictionary_id, :search_combinations_attributes
|
36
|
+
end
|
37
|
+
|
38
|
+
# Instance Methods
|
39
|
+
def initialize(*args)
|
40
|
+
super(*args)
|
41
|
+
end
|
42
|
+
|
43
|
+
def display_name
|
44
|
+
name.blank? ? "[No name specified]" : name
|
45
|
+
end
|
46
|
+
|
47
|
+
def parameterized_name
|
48
|
+
display_name.parameterize.underscore
|
49
|
+
end
|
50
|
+
|
51
|
+
def traverse
|
52
|
+
return unless combined_searches.any?
|
53
|
+
searches = []
|
54
|
+
combined_searches.each do |s|
|
55
|
+
searches << s
|
56
|
+
nested_searches = s.traverse
|
57
|
+
searches << nested_searches unless nested_searches.blank?
|
58
|
+
end
|
59
|
+
searches
|
60
|
+
end
|
61
|
+
|
62
|
+
def nested_searches
|
63
|
+
nested_searches = traverse || []
|
64
|
+
nested_searches.flatten.compact
|
65
|
+
end
|
66
|
+
|
67
|
+
def parameter_categories
|
68
|
+
search_parameters.map{|p| p.parameter.parameter_category unless p.parameter.blank?}.uniq
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_conditions
|
72
|
+
search_models = {}
|
73
|
+
all_search_parameters = nested_searches.map { |ns| ns.search_parameters }.flatten
|
74
|
+
all_search_parameters.concat(search_parameters).flatten!
|
75
|
+
|
76
|
+
all_search_parameters.each do |search_parameter|
|
77
|
+
search_models[search_parameter.parameter.search_model] = { :search_parameters => [], :conditions => nil } unless search_models.has_key?(search_parameter.parameter.search_model)
|
78
|
+
search_models[search_parameter.parameter.search_model][:search_parameters] << search_parameter
|
79
|
+
end
|
80
|
+
|
81
|
+
search_models.each do |k,v|
|
82
|
+
predicates = []
|
83
|
+
arguments = []
|
84
|
+
|
85
|
+
v[:search_parameters].each do |search_parameter|
|
86
|
+
sql = search_parameter.to_sql unless search_parameter.search_parameter_values.empty?
|
87
|
+
unless sql.nil?
|
88
|
+
predicates << sql[:predicates]
|
89
|
+
arguments << sql[:values] unless sql[:values].blank?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
search_models[k][:conditions] = [predicates.join(' and '), *flatten_arguments(arguments)]
|
94
|
+
end
|
95
|
+
search_models
|
96
|
+
end
|
97
|
+
|
98
|
+
def flatten_arguments(arguments)
|
99
|
+
args = []
|
100
|
+
arguments.each do |a|
|
101
|
+
a.each do |b|
|
102
|
+
args << b
|
103
|
+
end
|
104
|
+
end
|
105
|
+
args
|
106
|
+
end
|
107
|
+
|
108
|
+
def disabled?
|
109
|
+
return false unless persisted?
|
110
|
+
if export_parameters.select{|ep| ep.disabled?}.any?
|
111
|
+
warnings.add(:base, "Search uses deleted export parameters")
|
112
|
+
return true
|
113
|
+
end
|
114
|
+
deleted? ||
|
115
|
+
dictionary.deleted? ||
|
116
|
+
search_parameters.select{|sp| sp.disabled?}.any? ||
|
117
|
+
search_combinations.select{|sc| sc.disabled?}.any?
|
118
|
+
end
|
119
|
+
|
120
|
+
def searched_model?(model_name)
|
121
|
+
conditions.has_key?(model_name)
|
122
|
+
end
|
123
|
+
|
124
|
+
def conditions(force=false)
|
125
|
+
@conditions = self.to_conditions if @conditions.blank? || force
|
126
|
+
@conditions
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
def validate_search_parameters
|
131
|
+
if self.search_parameters.size < 1 || self.search_parameters.all?{|search_parameter| search_parameter.marked_for_destruction? }
|
132
|
+
errors.add(:base,"Search should have at least one search criteria.")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def update_associations
|
137
|
+
[search_parameters, export_parameters, search_combinations].each do |accociated_records|
|
138
|
+
accociated_records.each do |r|
|
139
|
+
r.deleted_at = Time.now
|
140
|
+
r.save
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Discerner
|
2
|
+
module Methods
|
3
|
+
module Models
|
4
|
+
module SearchCombination
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, SoftDelete
|
7
|
+
base.send :include, Warning
|
8
|
+
|
9
|
+
# Associations
|
10
|
+
base.send :belongs_to, :operator, :inverse_of => :search_combinations
|
11
|
+
base.send :belongs_to, :search, :inverse_of => :search_combinations, :foreign_key => :search_id
|
12
|
+
base.send :belongs_to, :combined_search, :foreign_key => :combined_search_id, :class_name => 'Discerner::Search'
|
13
|
+
|
14
|
+
# Scopes
|
15
|
+
base.send(:scope, :ordered_by_display_order, -> { base.order('discerner_search_combinations.display_order ASC') })
|
16
|
+
|
17
|
+
# Validations
|
18
|
+
base.send :validates_presence_of, :search, :combined_search
|
19
|
+
base.send :validate, :validate_searches
|
20
|
+
|
21
|
+
# Whitelisting attributes
|
22
|
+
base.send :attr_accessible, :combined_search_id, :display_order, :operator_id, :search_id, :search, :combined_search
|
23
|
+
end
|
24
|
+
|
25
|
+
# Instance Methods
|
26
|
+
def initialize(*args)
|
27
|
+
super(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate_searches
|
31
|
+
return if self.search_id.blank? || self.combined_search_id.blank?
|
32
|
+
errors.add(:base,"Search cannot be combined with itself.") if self.search_id == self.combined_search_id
|
33
|
+
end
|
34
|
+
|
35
|
+
def disabled?
|
36
|
+
return false unless persisted?
|
37
|
+
return true if deleted?
|
38
|
+
if combined_search.deleted?
|
39
|
+
warnings.add(:base, "Combined search has been deleted and has to be removed from the search")
|
40
|
+
return true
|
41
|
+
elsif combined_search.disabled?
|
42
|
+
warnings.add(:base, "Combined search has been disabled and has to be removed from the search")
|
43
|
+
return true
|
44
|
+
end
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|